﻿<?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++博客-小默-随笔分类-Windows</title><link>http://www.cppblog.com/momoxiao/category/14763.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 03 Nov 2010 10:21:39 GMT</lastBuildDate><pubDate>Wed, 03 Nov 2010 10:21:39 GMT</pubDate><ttl>60</ttl><item><title>【转】硬盘分区</title><link>http://www.cppblog.com/momoxiao/archive/2010/11/02/132183.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Tue, 02 Nov 2010 12:38:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/11/02/132183.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/132183.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/11/02/132183.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/132183.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/132183.html</trackback:ping><description><![CDATA[
		<textarea>
http://linux.chinaunix.net/bbs/thread-1134533-1-1.html
marsaber

--------

主分区只有1-4
也可以，主分区1-3，一个扩展分区，扩展分区下再划分若干分区。

==============================================================
主分区：一块物理硬盘上可以被独立使用的一部分，一个硬盘最多可以有4个主分区。
扩展分区：为了突破一个物理硬盘只能有4个分区的限制，引入了扩展分区。扩展分区和主分区的地位相当，但是扩展分区本身不能被直接使用，然而可以被继续划分成多个逻辑分区。
逻辑分区：逻辑分区可以有任意多个，但是不能独立存在，多个连续的逻辑分区可做为一个扩展分区。一个硬盘只能有一个扩展分区。
总结：也就是说，在一个物理硬盘上主分区和扩展分区加在一起最多仍然只有4个。但是扩展分区可以继续被划分成逻辑分区，而对多数用户而言，其实主分区和逻辑分区在使用上是没什么区别的。这样就达到了一快硬盘几乎可以有无限个分区的目的。
</textarea>
<img src ="http://www.cppblog.com/momoxiao/aggbug/132183.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-11-02 20:38 <a href="http://www.cppblog.com/momoxiao/archive/2010/11/02/132183.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows APC机制zzz</title><link>http://www.cppblog.com/momoxiao/archive/2010/03/18/109992.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Thu, 18 Mar 2010 07:09:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/03/18/109992.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/109992.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/03/18/109992.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/109992.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/109992.html</trackback:ping><description><![CDATA[前两篇漫谈中讲到，除ntdll.dll外，在启动一个新进程运行时，PE格式DLL映像的装入和动态连接是由ntdll.dll中的函数 LdrInitializeThunk()作为APC函数执行而完成的。这就牵涉到了Windows的APC机制，APC是&#8220;异步过程调用 (Asyncroneus Procedure Call)&#8221;的缩写。从大体上说，Windows的APC机制相当于Linux的Signal机制，实质上是一种对于应用软件(线程)的&#8220;软件中断&#8221;机制。但是读者将会看到，APC机制至少在形式上与软件中断机制还是有相当的区别，而称之为&#8220;异步过程调用&#8221;确实更为贴切。<br>APC与系统调用是密切连系在一起的，在这个意义上APC是系统调用界面的一部分。然而APC又与设备驱动有着很密切的关系。例如，ntddk.h中提供&#8220;写文件&#8221;系统调用ZwWriteFile()、即NtWriteFile()的调用界面为：
<p>&nbsp;</p>
<p>CODE:<br>NTSYSAPI<br>NTSTATUS<br>NTAPI<br>ZwWriteFile(<br>IN HANDLE FileHandle,<br>IN HANDLE Event OPTIONAL,<br>IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,<br>IN PVOID ApcContext OPTIONAL,<br>OUT PIO_STATUS_BLOCK IoStatusBlock,<br>IN PVOID Buffer,<br>IN ULONG Length,<br>IN PLARGE_INTEGER ByteOffset OPTIONAL,<br>IN PULONG Key OPTIONAL<br>);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里有个参数ApcRoutine，这是一个函数指针。什么时候要用到这个指针呢？原来，文件操作有&#8220;同步&#8221;和&#8220;异步&#8221;之分。普通的写文件操作是同步写，启动这种操作的线程在内核进行写文件操作期间被&#8220;阻塞(blocked)&#8221;而进入&#8220;睡眠&#8221;，直到设备驱动完成了操作以后才又将该线程&#8220;唤醒&#8221;而从系统调用返回。但是，如果目标文件是按异步操作打开的，即在通过W32的API函数CreateFile()打开目标文件时把调用参数 dwFlagsAndAttributes设置成FILE_FLAG_OVERLAPPED，那么调用者就不会被阻塞，而是把事情交给内核、不等实际的操作完成就返回了。但是此时要把ApcRoutine设置成指向某个APC函数。这样，当设备驱动完成实际的操作时，就会使调用者线程执行这个APC函数，就像是发生了一次中断。执行该APC函数时的调用界面为：</p>
<p>&nbsp;</p>
<p>CODE:<br>typedef<br>VOID<br>(NTAPI *PIO_APC_ROUTINE) (IN PVOID ApcContext,<br>IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里的指针ApcContext就是NtWriteFile()调用界面上传下来的，至于作什么解释、起什么作用，那是包括APC函数在内的用户软件自己的事，内核只是把它传递给APC函数。<br>在这个过程中，把ApcRoutine设置成指向APC函数相当于登记了一个中断服务程序，而设备驱动在完成实际的文件操作后就向调用者线程发出相当于中断请求的&#8220;APC请求&#8221;，使其执行这个APC函数。<br>从这个角度说，APC机制又应该说是设备驱动框架的一部分。事实上，读者以后还会看到，APC机制与设备驱动的关系比这里所见的还要更加密切。此外，APC机制与异常处理的关系也很密切。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不仅内核可以向一个线程发出APC请求，别的线程、乃至目标线程自身也可以发出这样的请求。Windows为应用程序提供了一个函数QueueUserAPC()，就是用于此项目的，下面是ReactOS中这个函数的代码：</p>
<p>&nbsp;</p>
<p>CODE:<br>DWORD STDCALL<br>QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)<br>{<br>NTSTATUS Status;</p>
<p>Status = NtQueueApcThread(hThread, IntCallUserApc,<br>pfnAPC, (PVOID)dwData, NULL);<br>if (Status)<br>SetLastErrorByStatus(Status);</p>
<p>return NT_SUCCESS(Status);<br>}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 参数pfnAPC是函数指针，这就是APC函数。另一个参数hThread是指向目标线程对象(已打开)的Handle，这可以是当前线程本身，也可以是同一进程中别的线程，还可以是别的进程中的某个线程。值得注意的是：如果目标线程在另一个进程中，那么pfnAPC必须是这个函数在目标线程所在用户空间的地址，而不是这个函数在本线程所在空间的地址。最后一个参数dwData则是需要传递给APC函数的参数。<br>这里的NtQueueApcThread()是个系统调用。&#8220;Native API&#8221;书中有关于NtQueueApcThread()的一些说明。这个系统调用把一个&#8220;用户APC请求&#8221;挂入目标线程的APC队列(更确切地说，是把一个带有函数指针的数据结构挂入队列)。注意其第二个参数是需要执行的APC函数指针，本该是pfnAPC，这里却换成了函数 IntCallUserApc()，而pfnAPC倒变成了第三个参数，成了需要传递给IntCallUserApc()的参数之一。 IntCallUserApc()是kernel32.dll内部的一个函数，但是并未引出，所以不能从外部直接加以调用。<br>APC是针对具体线程、要求由具体线程加以执行的，所以每个线程都有自己的APC队列。内核中代表着线程的数据结构是ETHREAD，而ETHREAD中的第一个成分Tcb是KTHREAD数据结构，线程的APC队列就在KTHREAD里面：</p>
<p>&nbsp;</p>
<p>CODE:<br>typedef struct _KTHREAD<br>{<br>. . . . . .<br>/* Thread state (one of THREAD_STATE_xxx constants below) */ UCHAR State; /* 2D */ BOOLEAN Alerted[2]; /* 2E */ . . . . . .<br>KAPC_STATE ApcState; /* 34 */ ULONG ContextSwitches; /* 4C */ . . . . . .<br>ULONG KernelApcDisable; /* D0 */ . . . . . .<br>PKQUEUE Queue; /* E0 */ KSPIN_LOCK ApcQueueLock; /* E4 */ . . . . . .<br>PKAPC_STATE ApcStatePointer[2]; /* 12C */ . . . . . .<br>KAPC_STATE SavedApcState; /* 140 */ UCHAR Alertable; /* 158 */ UCHAR ApcStateIndex; /* 159 */ UCHAR ApcQueueable; /* 15A */ . . . . . .<br>KAPC SuspendApc; /* 160 */ . . . . . .<br>} KTHREAD;</p>
<p>Microsoft 并不公开这个数据结构的定义，所以ReactOS代码中对这个数据结构的定义带有逆向工程的痕迹，每一行后面的十六进制数值就是相应结构成分在数据结构中的位移。这里我们最关心的是ApcState，这又是一个数据结构、即KAPC_STATE。可以看出，KAPC_STATE的大小是0x18字节。其定义如下：</p>
<p>&nbsp;</p>
<p>CODE:<br>typedef struct _KAPC_STATE {<br>LIST_ENTRY ApcListHead[2];<br>PKPROCESS Process;<br>BOOLEAN KernelApcInProgress;<br>BOOLEAN KernelApcPending;<br>BOOLEAN UserApcPending;<br>} KAPC_STATE, *PKAPC_STATE, *__restrict PRKAPC_STATE;</p>
<p>显然，这里的ApcListHead就是APC队列头。不过这是个大小为2的数组，说明实际上(每个线程)有两个APC队列。这是因为APC函数分为用户 APC和内核APC两种，各有各的队列。所谓用户APC，是指相应的APC函数位于用户空间、在用户空间执行；而内核APC，则相应的APC函数为内核函数。<br>读者也许已经注意到，KTHREAD结构中除ApcState外还有SavedApcState也是KAPC_STATE数据结构。此外还有 ApcStatePointer[2]和ApcStateIndex两个结构成分。这是干什么用的呢？原来，在Windows的内核中，一个线程可以暂时 &#8220;挂靠(Attach)&#8221;到另一个进程的地址空间。比方说，线程T本来是属于进程A的，当这个线程在内核中运行时，如果其活动与用户空间有关(APC就是与用户空间有关)，那么当时的用户空间应该就是进程A的用户空间。但是Windows内核允许一些跨进程的操作(例如将ntdll.dll的映像装入新创进程B的用户空间并对其进行操作)，所以有时候需要把当时的用户空间切换到别的进程(例如B) 的用户空间，这就称为&#8220;挂靠(Attach)&#8221;，对此我将另行撰文介绍。在当前线程挂靠在另一个进程的期间，既然用户空间是别的进程的用户空间，挂在队列中的APC请求就变成&#8220;牛头不对马嘴&#8221;了，所以此时要把这些队列转移到别的地方，以免乱套，然后在回到原进程的用户空间时再于恢复。那么转移到什么地方呢？就是SavedApcState。当然，还要有状态信息说明本线程当前是处于&#8220;原始环境&#8221;还是&#8220;挂靠环境&#8221;，这就是ApcStateIndex的作用。代码中为SavedApcState的值定义了一种枚举类型：</p>
<p>&nbsp;</p>
<p>CODE:<br>typedef enum _KAPC_ENVIRONMENT<br>{<br>OriginalApcEnvironment,<br>AttachedApcEnvironment,<br>CurrentApcEnvironment<br>} KAPC_ENVIRONMENT;</p>
<p>实际可用于ApcStateIndex的只是OriginalApcEnvironment和AttachedApcEnvironment，即0和1。读者也许又要问，在挂靠环境下原来的APC队列确实不适用了，但不去用它就是，何必要把它转移呢？再说，APC队列转移以后，ApcState不是空下来不用了吗？问题在于，在挂靠环境下也可能会有(针对所挂靠进程的)APC请求(不过当然不是来自用户空间)，所以需要有用于两种不同环境的APC队列，于是便有了ApcState和SavedApcState。进一步，为了提供操作上的灵活性，又增加了一个KAPC_STATE指针数组 ApcStatePointer[2]，就用ApcStateIndex的当前值作为下标，而数组中的指针则根据情况可以分别指向两个APC_STATE 数据结构中的一个。<br>这样，以ApcStateIndex的当前数值为下标，从指针数组ApcStatePointer[2]中就可以得到指向ApcState或 SavedApcState的指针，而要求把一个APC请求挂入队列时则可以指定是要挂入哪一个环境的队列。实际上，当ApcStateIndex的值为 OriginalApcEnvironment、即0时，使用的是ApcState；为AttachedApcEnvironment、即1时，则用的是 SavedApcState。<br>每当要求挂入一个APC函数时，不管是用户APC还是内核APC，内核都要为之准备好一个KAPC数据结构，并将其挂入相应的队列。</p>
<p>&nbsp;</p>
<p>CODE:<br>typedef struct _KAPC<br>{<br>CSHORT Type;<br>CSHORT Size;<br>ULONG Spare0;<br>struct _KTHREAD* Thread;<br>LIST_ENTRY ApcListEntry;<br>PKKERNEL_ROUTINE KernelRoutine;<br>PKRUNDOWN_ROUTINE RundownRoutine;<br>PKNORMAL_ROUTINE NormalRoutine;<br>PVOID NormalContext;<br>PVOID SystemArgument1;<br>PVOID SystemArgument2;<br>CCHAR ApcStateIndex;<br>KPROCESSOR_MODE ApcMode;<br>BOOLEAN Inserted;<br>} KAPC, *PKAPC;</p>
<p>结构中的ApcListEntry就是用来将KAPC结构挂入队列的。注意这个数据结构中有三个函数指针，即KernelRoutine、 RundownRoutine、NormalRoutine。其中只有NormalRoutine才指向(执行)APC函数的请求者所提供的函数，其余两个都是辅助性的。以NtQueueApcThread()为例，其请求者(调用者)QueueUserAPC()所提供的函数是 IntCallUserApc()，所以NormalRoutine应该指向这个函数。注意真正的请求者其实是QueueUserAPC()的调用者，真正的目标APC函数也并非IntCallUserApc()，而是前面的函数指针pfnAPC所指向的函数，而IntCallUserApc()起着类似于&#8220;门户&#8221;的作用。</p>
<p>现在我们可以往下看系统调用NtQueueApcThread()的实现了。</p>
<p>&nbsp;</p>
<p>CODE:<br>NTSTATUS<br>STDCALL<br>NtQueueApcThread(HANDLE ThreadHandle, PKNORMAL_ROUTINE ApcRoutine,<br>PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)<br>{<br>PKAPC Apc;<br>PETHREAD Thread;<br>KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();<br>NTSTATUS Status;</p>
<p>/* Get ETHREAD from Handle */ Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_SET_CONTEXT,<br>PsThreadType, PreviousMode, (PVOID)&amp;Thread, NULL);<br>. . . . . .<br>/* Allocate an APC */ Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('P', 's', 'a', 'p'));<br>. . . . . .<br>/* Initialize and Queue a user mode apc (always!) */ KeInitializeApc(Apc, &amp;Thread-&gt;Tcb, OriginalApcEnvironment,<br>KiFreeApcRoutine, NULL, ApcRoutine, UserMode, NormalContext);</p>
<p>if (!KeInsertQueueApc(Apc, SystemArgument1, SystemArgument2,<br>IO_NO_INCREMENT))<br>{<br>Status = STATUS_UNSUCCESSFUL;</p>
<p>} else {<br>Status = STATUS_SUCCESS;<br>}</p>
<p>/* Dereference Thread and Return */ ObDereferenceObject(Thread);<br>return Status;<br>}</p>
<p>先看调用参数。第一个参数是代表着某个已打开线程的Handle，这说明所要求的APC函数的执行者、即目标线程、可以是另一个线程，而不必是请求者线程本身。第二个参数不言自明。第三个参数NormalContext，以及后面的两个参数，则是准备传递给APC函数的参数，至于怎样解释和使用这几个参数是 APC函数的事。看一下前面QueueUserAPC()的代码，就可以知道这里的APC函数是IntCallUserApc()，而准备传给它的参数分别为pfnAPC、dwData、和NULL，前者是真正的目标APC函数指针，后两者是要传给它的参数。<br>根据Handle找到目标线程的ETHREAD数据结构以后，就为APC函数分配一个KAPC数据结构，并通过KeInitializeApc()加以初始化。</p>
<p>&nbsp;</p>
<p>CODE:<br>[NtQueueApcThread() &gt; KeInitializeApc()]</p>
<p>VOID<br>STDCALL<br>KeInitializeApc(IN PKAPC Apc,<br>IN PKTHREAD Thread,<br>IN KAPC_ENVIRONMENT TargetEnvironment,<br>IN PKKERNEL_ROUTINE KernelRoutine,<br>IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,<br>IN PKNORMAL_ROUTINE NormalRoutine,<br>IN KPROCESSOR_MODE Mode,<br>IN PVOID Context)<br>{<br>. . . . . .</p>
<p>/* Set up the basic APC Structure Data */ RtlZeroMemory(Apc, sizeof(KAPC));<br>Apc-&gt;Type = ApcObject;<br>Apc-&gt;Size = sizeof(KAPC);</p>
<p>/* Set the Environment */ if (TargetEnvironment == CurrentApcEnvironment) {</p>
<p>Apc-&gt;ApcStateIndex = Thread-&gt;ApcStateIndex;</p>
<p>} else {</p>
<p>Apc-&gt;ApcStateIndex = TargetEnvironment;<br>}</p>
<p>/* Set the Thread and Routines */ Apc-&gt;Thread = Thread;<br>Apc-&gt;KernelRoutine = KernelRoutine;<br>Apc-&gt;RundownRoutine = RundownRoutine;<br>Apc-&gt;NormalRoutine = NormalRoutine;</p>
<p>/* Check if this is a Special APC, in which case we use KernelMode and no Context */ if (ARGUMENT_PRESENT(NormalRoutine)) {</p>
<p>Apc-&gt;ApcMode = Mode;<br>Apc-&gt;NormalContext = Context;</p>
<p>} else {</p>
<p>Apc-&gt;ApcMode = KernelMode;<br>} <br>}</p>
<p>这段代码本身很简单，但是有几个问题需要结合前面NtQueueApcThread()的代码再作些说明。<br>首先，从NtQueueApcThread()传下来的KernelRoutine是KiFreeApcRoutine()，顾名思义这是在为将来释放PKAPC数据结构做好准备，而RundownRoutine是NULL。<br>其次，参数TargetEnvironment说明要求挂入哪一种环境下的APC队列。实际传下来的值是OriginalApcEnvironment，表示是针对原始环境、即当前线程所属(而不是所挂靠)进程的。注意代码中所设置的是Apc-&gt;ApcStateIndex、即PKAPC数据结构中的ApcStateIndex字段，而不是KTHREAD结构中的ApcStateIndex字段。另一方面，ApcStateIndex的值只能是 OriginalApcEnvironment或AttachedApcEnvironment，如果所要求的是 CurrentApcEnvironment就要从Thread-&gt;ApcStateIndex获取当前的环境值。<br>最后，APC请求的模式Mode是UserMode。但是有个例外，那就是：如果指针NormalRoutine为0，那么实际的模式变成了 KernelMode。这是因为在这种情况下没有用户空间APC函数可以执行，唯一将得到执行的是KernelRoutine，在这里是 KiFreeApcRoutine()。这里的宏操作ARGUMENT_PRESENT定义为：</p>
<p>&nbsp;</p>
<p>CODE:<br>#define ARGUMENT_PRESENT(ArgumentPointer) \<br>((BOOLEAN) ((PVOID)ArgumentPointer != (PVOID)NULL))</p>
<p>回到NtQueueApcThread()代码中，下一步就是根据Apc-&gt;ApcStateIndex、Apc-&gt;Thread、和Apc- &gt;ApcMode把准备好的KAPC结构挂入相应的队列。根据APC请求的具体情况，有时候要插在队列的前头，一般则挂在队列的尾部。限于篇幅，我们在这里就不看KeInsertQueueApc()的代码了；虽然这段代码中有一些特殊的处理，但都不是我们此刻所特别关心的。<br>如果跟Linux的Signal机制作一类比，那么NtQueueApcThread()相当于设置Signal处理函数(或中断服务程序)。在 Linux里面，Signal处理函数的执行需要受到某种触发，例如收到了别的线程或某个内核成分发来的信号；而执行Signal处理函数的时机则是在 CPU从内核返回目标线程的用户空间程序的前夕。可是Windows的APC机制与此有所不同，一般来说，只要把APC请求挂入了队列，就不再需要触发，而只是等待执行的时机。对于用户APC请求，这时机同样也是在CPU从内核返回目标线程用户空间程序的前夕(对于内核APC则有所不同)。所以，在某种意义上，把一个APC请求挂入队列，就同时意味着受到了触发。对于系统调用NtQueueApcThread()，我们可以理解为是把APC函数的设置与触发合在了一起。而对于异步的文件读写，则APC函数的设置与触发是分开的，内核先把APC函数记录在别的数据结构中，等实际的文件读写完成以后才把APC 请求挂入队列，此时实际上只是触发其运行。不过那已是属于设备驱动框架的事了。所以，一旦把APC请求挂入队列，就只是等待执行时机的问题了。从这个意义上说，&#8220;异步过程调用&#8221;还真不失为贴切的称呼。</p>
<p>下面就来看执行APC的时机，那是在(系统调用、中断、或异常处理之后)从内核返回用户空间的途中。</p>
<p>&nbsp;</p>
<p>CODE:<br>_KiServiceExit:</p>
<p>/* Get the Current Thread */ cli<br>movl %fs:KPCR_CURRENT_THREAD, %esi</p>
<p>/* Deliver APCs only if we were called from user mode */ testb $1, KTRAP_FRAME_CS(%esp)<br>je KiRosTrapReturn</p>
<p>/* And only if any are actually pending */ cmpb $0, KTHREAD_PENDING_USER_APC(%esi)<br>je KiRosTrapReturn</p>
<p>/* Save pointer to Trap Frame */ movl %esp, %ebx</p>
<p>/* Raise IRQL to APC_LEVEL */ movl $1, %ecx<br>call @KfRaiseIrql@4</p>
<p>/* Save old IRQL */ pushl %eax</p>
<p>/* Deliver APCs */ sti<br>pushl %ebx<br>pushl $0<br>pushl $UserMode<br>call <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#95;&#75;&#105;&#68;&#101;&#108;&#105;&#118;&#101;&#114;&#65;&#112;&#99;&#64;&#49;&#50;"><u><font color="#0000ff">_KiDeliverApc@12</font></u></a><br>cli</p>
<p>/* Return to old IRQL */ popl %ecx<br>call @KfLowerIrql@4<br>. . . . . .</p>
<p>这是内核中处理系统调用返回和中断/异常返回的代码。在返回前夕，这里先通过%fs:KPCR_CURRENT_THREAD取得指向当前线程的ETHREAD(从而KTHREAD)的指针，然后依次检查：<br>● 即将返回的是否用户空间。<br>● 是否有用户APC请求正在等待执行(KTHREAD_PENDING_USER_APC是 ApcState.KernelApcPending在KTHREAD数据结构中的位移)。<br>要是通过了这两项检查，执行针对当前线程的APC请求的时机就到了，于是就调用KiDeliverApc()去&#8220;投递&#8221;APC函数，这跟Linux中对 Signal的处理又是十分相似的。注意在调用这个函数的前后还分别调用了KfRaiseIrql()和KfLowerIrql()，这是为了在执行 KiDeliverApc()期间让内核的&#8220;中断请求级别&#8221;处于APC_LEVEL，执行完以后再予恢复。我们现在暂时不关心&#8220;中断请求级别&#8221;，以后会回到这个问题上。<br>前面讲过，KTHREAD中有两个KAPC_STATE数据结构，一个是ApcState，另一个是SavedApcState，二者都有APC队列，但是要投递的只是ApcState中的队列。<br>注意在call指令前面压入堆栈的三个参数，特别是首先压入堆栈的%ebx，它指向(系统空间)堆栈上的&#8220;中断现场&#8221;、或称&#8220;框架&#8221;，即CPU进入本次中断或系统调用时各寄存器的值，这就是下面KiDeliverApc()的调用参数TrapFrame。<br>下面我们看KiDeliverApc()的代码。</p>
<p>&nbsp;</p>
<p>CODE:<br>[KiDeliverApc()]</p>
<p>VOID<br>STDCALL<br>KiDeliverApc(KPROCESSOR_MODE DeliveryMode,<br>PVOID Reserved,<br>PKTRAP_FRAME TrapFrame)<br>{<br>PKTHREAD Thread = KeGetCurrentThread();<br>. . . . . .</p>
<p>ASSERT_IRQL_EQUAL(APC_LEVEL);</p>
<p>/* Lock the APC Queue and Raise IRQL to Synch */ KeAcquireSpinLock(&amp;Thread-&gt;ApcQueueLock, &amp;OldIrql);</p>
<p>/* Clear APC Pending */ Thread-&gt;ApcState.KernelApcPending = FALSE;</p>
<p>/* Do the Kernel APCs first */ while (!IsListEmpty(&amp;Thread-&gt;ApcState.ApcListHead[KernelMode])) {<br>/* Get the next Entry */ ApcListEntry = Thread-&gt;ApcState.ApcListHead[KernelMode].Flink;<br>Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);</p>
<p>/* Save Parameters so that it's safe to free the Object in Kernel Routine*/ NormalRoutine = Apc-&gt;NormalRoutine;<br>KernelRoutine = Apc-&gt;KernelRoutine;<br>NormalContext = Apc-&gt;NormalContext;<br>SystemArgument1 = Apc-&gt;SystemArgument1;<br>SystemArgument2 = Apc-&gt;SystemArgument2;</p>
<p>/* Special APC */ if (NormalRoutine == NULL) {<br>/* Remove the APC from the list */ Apc-&gt;Inserted = FALSE;<br>RemoveEntryList(ApcListEntry);</p>
<p>/* Go back to APC_LEVEL */ KeReleaseSpinLock(&amp;Thread-&gt;ApcQueueLock, OldIrql);</p>
<p>/* Call the Special APC */ DPRINT("Delivering a Special APC: %x\n", Apc);<br>KernelRoutine(Apc, &amp;NormalRoutine, &amp;NormalContext,<br>&amp;SystemArgument1, &amp;SystemArgument2);</p>
<p>/* Raise IRQL and Lock again */ KeAcquireSpinLock(&amp;Thread-&gt;ApcQueueLock, &amp;OldIrql);</p>
<p>} else {</p>
<p>/* Normal Kernel APC */ if (Thread-&gt;ApcState.KernelApcInProgress || Thread-&gt;KernelApcDisable)<br>{<br>/*<br>* DeliveryMode must be KernelMode in this case, since one may not<br>* return to umode while being inside a critical section or while<br>* a regular kmode apc is running (the latter should be impossible btw).<br>* -Gunnar<br>*/ ASSERT(DeliveryMode == KernelMode);</p>
<p>KeReleaseSpinLock(&amp;Thread-&gt;ApcQueueLock, OldIrql);<br>return;<br>}</p>
<p>/* Dequeue the APC */ RemoveEntryList(ApcListEntry);<br>Apc-&gt;Inserted = FALSE;</p>
<p>/* Go back to APC_LEVEL */ KeReleaseSpinLock(&amp;Thread-&gt;ApcQueueLock, OldIrql);</p>
<p>/* Call the Kernel APC */ DPRINT("Delivering a Normal APC: %x\n", Apc);<br>KernelRoutine(Apc,<br>&amp;NormalRoutine,<br>&amp;NormalContext,<br>&amp;SystemArgument1,<br>&amp;SystemArgument2);</p>
<p>/* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */ if (NormalRoutine != NULL) {</p>
<p>/* At Passive Level, this APC can be prempted by a Special APC */ Thread-&gt;ApcState.KernelApcInProgress = TRUE;<br>KeLowerIrql(PASSIVE_LEVEL);</p>
<p>/* Call and Raise IRQ back to APC_LEVEL */ DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc);<br>NormalRoutine(&amp;NormalContext, &amp;SystemArgument1, &amp;SystemArgument2);<br>KeRaiseIrql(APC_LEVEL, &amp;OldIrql);<br>}</p>
<p>/* Raise IRQL and Lock again */ KeAcquireSpinLock(&amp;Thread-&gt;ApcQueueLock, &amp;OldIrql);<br>Thread-&gt;ApcState.KernelApcInProgress = FALSE;<br>}<br>} //end while</p>
<p>参数DeliveryMode表示需要&#8220;投递&#8221;哪一种APC，可以是UserMode，也可以是KernelMode。不过，KernelMode确实表示只要求执行内核APC，而UserMode却表示在执行内核APC之外再执行用户APC。这里所谓&#8220;执行内核APC&#8221;是执行内核APC队列中的所有请求，而&#8220;执行用户APC&#8221;却只是执行用户APC队列中的一项。<br>所以首先检查内核模式APC队列，只要非空就通过一个while循环处理其所有的APC请求。队列中的每一项(如果队列非空的话)、即每一个APC请求都是KAPC结构，结构中有三个函数指针，但是这里只涉及其中的两个。一个是NormalRoutine，若为非0就是指向一个实质性的内核APC函数。另一个是KernelRoutine，指向一个辅助性的内核APC函数，这个指针不会是0，否则这个KAPC结构就不会在队列中了(注意 KernelRoutine与内核模式NormalRoutine的区别)。NormalRoutine为0是一种特殊的情况，在这种情况下 KernelRoutine所指的内核函数无条件地得到调用。但是，如果NormalRoutine非0，那么首先得到调用的是 KernelRoutine，而指针NormalRoutine的地址是作为参数传下去的。KernelRoutine的执行有可能改变这个指针的值。这样，如果执行KernelRoutine以后NormalRoutine仍为非0，那就说明需要加以执行，所以通过这个函数指针予以调用。不过，内核 APC函数的执行是在PASSIVE_LEVEL级别上执行的，所以对NormalRoutine的调用前有KeLowerIrql()、后有 KeRaiseIrql()，前者将CPU的运行级别调整为PASSIVE_LEVEL，后者则将其恢复为APC_LEVEL。<br>执行完内核APC队列中的所有请求以后，如果调用参数DeliveryMode为UserMode的话，就轮到用户APC了。我们继续往下看：</p>
<p>&nbsp;</p>
<p>CODE:<br>[KiDeliverApc()]</p>
<p>/* Now we do the User APCs */ if ((!IsListEmpty(&amp;Thread-&gt;ApcState.ApcListHead[UserMode])) &amp;<br>(DeliveryMode == UserMode) &amp;&amp; (Thread-&gt;ApcState.UserApcPending == TRUE)) {</p>
<p>/* It's not pending anymore */ Thread-&gt;ApcState.UserApcPending = FALSE;</p>
<p>/* Get the APC Object */ ApcListEntry = Thread-&gt;ApcState.ApcListHead[UserMode].Flink;<br>Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);</p>
<p>/* Save Parameters so that it's safe to free the Object in Kernel Routine*/ NormalRoutine = Apc-&gt;NormalRoutine;<br>KernelRoutine = Apc-&gt;KernelRoutine;<br>NormalContext = Apc-&gt;NormalContext;<br>SystemArgument1 = Apc-&gt;SystemArgument1;<br>SystemArgument2 = Apc-&gt;SystemArgument2;</p>
<p>/* Remove the APC from Queue, restore IRQL and call the APC */ RemoveEntryList(ApcListEntry);<br>Apc-&gt;Inserted = FALSE;</p>
<p>KeReleaseSpinLock(&amp;Thread-&gt;ApcQueueLock, OldIrql);<br>DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc);<br>KernelRoutine(Apc,<br>&amp;NormalRoutine,<br>&amp;NormalContext,<br>&amp;SystemArgument1,<br>&amp;SystemArgument2);</p>
<p>if (NormalRoutine == NULL) {<br>/* Check if more User APCs are Pending */ KeTestAlertThread(UserMode);<br>}else {<br>/* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */ DPRINT("Delivering a User APC: %x\n", Apc);<br>KiInitializeUserApc(Reserved,<br>TrapFrame,<br>NormalRoutine,<br>NormalContext,<br>SystemArgument1,<br>SystemArgument2);<br>}</p>
<p>} else {</p>
<p>/* Go back to APC_LEVEL */ KeReleaseSpinLock(&amp;Thread-&gt;ApcQueueLock, OldIrql);<br>}<br>}</p>
<p>当然，执行用户APC是有条件的。首先自然是用户APC队列非空，同时调用参数DeliveryMode必须是UserMode；并且ApcState中的UserApcPending为TRUE，表示队列中的请求确实是要求尽快加以执行的。<br>读者也许已经注意到，比之内核APC队列，对用户APC队列的处理有个显著的不同，那就是对用户APC队列并不是通过一个while循环处理队列中的所有请求，而是每次进入KiDeliverApc()只处理用户APC队列中的第一个请求。同样，这里也是只涉及两个函数指针，即NormalRoutine 和KernelRoutine，也是先执行KernelRoutine，并且KernelRoutine可以对指针NormalRoutine作出修正。但是再往下就不同了。<br>首先，如果执行完KernelRoutine(所指的函数)以后指针NormalRoutine为0，这里要执行KeTestAlertThread ()。这又是跟设备驱动有关的事(Windows术语中的Alert相当于Linux术语中的&#8220;唤醒&#8221;)，我们在这里暂不关心。<br>反之，如果指针NormalRoutine仍为非0，那么这里执行的是KiInitializeUserApc()，而不是直接调用 NormalRoutine所指的函数，因为NormalRoutine所指的函数是在用户空间，要等CPU回到用户空间才能执行，这里只是为其作好安排和准备。</p>
<p>&nbsp;</p>
<p>CODE:<br>[KiDeliverApc() &gt; KiInitializeUserApc()]</p>
<p>VOID<br>STDCALL<br>KiInitializeUserApc(IN PVOID Reserved,<br>IN PKTRAP_FRAME TrapFrame,<br>IN PKNORMAL_ROUTINE NormalRoutine,<br>IN PVOID NormalContext,<br>IN PVOID SystemArgument1,<br>IN PVOID SystemArgument2) <br>{<br>PCONTEXT Context;<br>PULONG Esp;</p>
<p>. . . . . .<br>/*<br>* Save the thread's current context (in other words the registers<br>* that will be restored when it returns to user mode) so the<br>* APC dispatcher can restore them later<br>*/ Context = (PCONTEXT)(((PUCHAR)TrapFrame-&gt;Esp) - sizeof(CONTEXT));<br>RtlZeroMemory(Context, sizeof(CONTEXT));<br>Context-&gt;ContextFlags = CONTEXT_FULL;<br>Context-&gt;SegGs = TrapFrame-&gt;Gs;<br>Context-&gt;SegFs = TrapFrame-&gt;Fs;<br>Context-&gt;SegEs = TrapFrame-&gt;Es;<br>Context-&gt;SegDs = TrapFrame-&gt;Ds;<br>Context-&gt;Edi = TrapFrame-&gt;Edi;<br>Context-&gt;Esi = TrapFrame-&gt;Esi;<br>Context-&gt;Ebx = TrapFrame-&gt;Ebx;<br>Context-&gt;Edx = TrapFrame-&gt;Edx;<br>Context-&gt;Ecx = TrapFrame-&gt;Ecx;<br>Context-&gt;Eax = TrapFrame-&gt;Eax;<br>Context-&gt;Ebp = TrapFrame-&gt;Ebp;<br>Context-&gt;Eip = TrapFrame-&gt;Eip;<br>Context-&gt;SegCs = TrapFrame-&gt;Cs;<br>Context-&gt;EFlags = TrapFrame-&gt;Eflags;<br>Context-&gt;Esp = TrapFrame-&gt;Esp;<br>Context-&gt;SegSs = TrapFrame-&gt;Ss;</p>
<p>/*<br>* Setup the trap frame so the thread will start executing at the<br>* APC Dispatcher when it returns to user-mode<br>*/ Esp = (PULONG)(((PUCHAR)TrapFrame-&gt;Esp) -<br>(sizeof(CONTEXT) + (6 * sizeof(ULONG))));<br>Esp[0] = 0xdeadbeef;<br>Esp[1] = (ULONG)NormalRoutine;<br>Esp[2] = (ULONG)NormalContext;<br>Esp[3] = (ULONG)SystemArgument1;<br>Esp[4] = (ULONG)SystemArgument2;<br>Esp[5] = (ULONG)Context;<br>TrapFrame-&gt;Eip = (ULONG)LdrpGetSystemDllApcDispatcher();<br>TrapFrame-&gt;Esp = (ULONG)Esp;<br>}</p>
<p>这个函数的名字取得不好，很容易让人把它跟前面的KeInitializeApc()相连系，实际上却完全是两码事。参数TrapFrame是由 KiDeliverApc()传下来的一个指针，指向用户空间堆栈上的&#8220;中断现场&#8221;。这里要做的事情就是在原有现场的基础上&#8220;注水&#8221;，伪造出一个新的现场，使得CPU返回用户空间时误认为中断(或系统调用)发生于进入APC函数的前夕，从而转向APC函数。<br>怎么伪造呢？首先使用户空间的堆栈指针Esp下移一个CONTEXT数据结构的大小，外加6个32位整数的位置(注意堆栈是由上向下伸展的)。换言之就是在用户空间堆栈上扩充出一个CONTEXT数据结构和6个32位整数。注意，TrapFrame是在系统空间堆栈上，而TrapFrame-&gt; Esp的值是用户空间的堆栈指针，所指向的是用户空间堆栈。所以这里扩充的是用户空间堆栈。这样，原先的用户堆栈下方是CONTEXT数据结构 Context，再往下就是那6个32位整数。然后把TrapFrame的内容保存在这个CONTEXT数据结构中，并设置好6个32位整数，那是要作为调用参数传递的。接着就把保存在TrapFrame中的Eip映像改成指向用户空间的一个特殊函数，具体的地址通过 LdrpGetSystemDllApcDispatcher()获取。这样，当CPU返回到用户空间时，就会从这个特殊函数&#8220;继续&#8221;执行。当然，也要调整TrapFrame中的用户空间堆栈指针Esp。<br>LdrpGetSystemDllApcDispatcher()只是返回一个(内核)全局量SystemDllApcDispatcher的值，这个值是个函数指针，指向ntdll.dll中的一个函数，是在映射ntdll.dll映像时设置好的。</p>
<p>&nbsp;</p>
<p>CODE:<br>PVOID LdrpGetSystemDllApcDispatcher(VOID)<br>{<br>return(SystemDllApcDispatcher);<br>}</p>
<p>与全局变量SystemDllApcDispatcher相似的函数指针有：<br>● SystemDllEntryPoint，指向LdrInitializeThunk()。<br>● SystemDllApcDispatcher，指向KiUserApcDispatcher()。<br>● SystemDllExceptionDispatcher，指向KiUserExceptionDispatcher()。<br>● SystemDllCallbackDispatcher，指向KiUserCallbackDispatcher()。<br>● SystemDllRaiseExceptionDispatche r，指向KiRaiseUserExceptionDispatcher()。<br>这些指针都是在LdrpMapSystemDll()中得到设置的。给定一个函数名的字符串，就可以通过一个函数LdrGetProcedureAddress()从(已经映射的)DLL映像中获取这个函数的地址(如果这个函数被引出的话)。<br>于是，CPU从KiDeliverApc()回到_KiServiceExit以后会继续完成其返回用户空间的行程，只是一到用户空间就栽进了圈套，那就是KiUserApcDispatcher()，而不是回到原先的断点上。关于原先断点的现场信息保存在用户空间堆栈上、并形成一个CONTEXT数据结构，但是&#8220;深埋&#8221;在6个32位整数的后面。而这6个32位整数的作用则为：<br>● Esp[0]的值为0xdeadbeef，用来模拟KiUserApcDispatcher()的返回地址。当然，这个地址是无效的，所以KiUserApcDispatcher()实际上是不会返回的。<br>● Esp[1]的值为NormalRoutine，在我们这个情景中指向&#8220;门户&#8221;函数IntCallUserApc()。<br>● Esp[2]的值为NormalContext，在我们这个情景中是指向实际APC函数的指针。<br>● 余类推。其中Esp[5]指向(用户)堆栈上的CONTEXT数据结构。<br>总之，用户堆栈上的这6个32位整数模拟了一次CPU在进入KiUserApcDispatcher()还没有来得及执行其第一条指令之前就发生了中断的假象，使得CPU在结束了KiDeliverApc()的执行、回到_KiServiceExit中继续前行、并最终回到用户空间时就进入 KiUserApcDispatcher()执行其第一条指令。<br>另一方面，对于该线程原来的上下文而言，则又好像是刚回到用户空间就发生了中断，而KiUserApcDispatcher()则相当于中断相应程序。</p>
<p>&nbsp;</p>
<p>CODE:<br>VOID STDCALL<br>KiUserApcDispatcher(PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,<br>PIO_STATUS_BLOCK Iosb, ULONG Reserved, PCONTEXT Context)<br>{<br>/* Call the APC */ ApcRoutine(ApcContext, Iosb, Reserved);<br>/* Switch back to the interrupted context */ NtContinue(Context, 1);<br>}</p>
<p>这里的第一个参数ApcRoutine指向IntCallUserApc()，第二个参数ApcContext指向真正的(目标)APC函数。</p>
<p>&nbsp;</p>
<p>CODE:<br>[KiUserApcDispatcher() &gt; IntCallUserApc()]</p>
<p>static void CALLBACK<br>IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)<br>{<br>PAPCFUNC pfnAPC = (PAPCFUNC)Function;<br>pfnAPC((ULONG_PTR)dwData);<br>}</p>
<p>可见，IntCallUserApc()其实并无必要，在KiUserApcDispatcher()中直接调用目标APC函数也无不可，这样做只是为将来可能的修改扩充提供一些方便和灵活性。从IntCallUserApc()回到KiUserApcDispatcher()，下面紧接着是系统调用 NtContinue()。</p>
<p>KiUserApcDispatcher()是不返回的。它之所以不返回，是因为对NtContinue()的调用不返回。正如代码中的注释所述， NtContinue()的作用是切换回被中断了的上下文，不过其实还不止于此，下面读者就会看到它还起着循环执行整个用户APC请求队列的作用。</p>
<p>&nbsp;</p>
<p>CODE:<br>[KiUserApcDispatcher() &gt; NtContinue()]</p>
<p>NTSTATUS STDCALL<br>NtContinue (IN PCONTEXT Context, IN BOOLEAN TestAlert)<br>{<br>PKTHREAD Thread = KeGetCurrentThread();<br>PKTRAP_FRAME TrapFrame = Thread-&gt;TrapFrame;<br>PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame-&gt;Edx;<br>PFX_SAVE_AREA FxSaveArea;<br>KIRQL oldIrql;</p>
<p>DPRINT("NtContinue: Context: Eip=0x%x, Esp=0x%x\n", Context-&gt;Eip, Context-&gt;Esp );<br>PULONG Frame = 0;<br>__asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );<br>. . . . . .</p>
<p>/*<br>* Copy the supplied context over the register information that was saved<br>* on entry to kernel mode, it will then be restored on exit<br>* FIXME: Validate the context<br>*/ KeContextToTrapFrame ( Context, TrapFrame );</p>
<p>/* Put the floating point context into the thread's FX_SAVE_AREA<br>* and make sure it is reloaded when needed.<br>*/ FxSaveArea = (PFX_SAVE_AREA)((ULONG_PTR)Thread-&gt;InitialStack &#8211;<br>sizeof(FX_SAVE_AREA));<br>if (KiContextToFxSaveArea(FxSaveArea, Context))<br>{<br>Thread-&gt;NpxState = NPX_STATE_VALID;<br>KeRaiseIrql(DISPATCH_LEVEL, &amp;oldIrql);<br>if (KeGetCurrentPrcb()-&gt;NpxThread == Thread)<br>{<br>KeGetCurrentPrcb()-&gt;NpxThread = NULL;<br>Ke386SetCr0(Ke386GetCr0() | X86_CR0_TS);<br>}<br>else<br>{<br>ASSERT((Ke386GetCr0() &amp; X86_CR0_TS) == X86_CR0_TS);<br>}<br>KeLowerIrql(oldIrql);<br>}</p>
<p>/* Restore the user context */ Thread-&gt;TrapFrame = PrevTrapFrame;<br>__asm__("mov %%ebx, %%esp;\n" "jmp _KiServiceExit": : "b" (TrapFrame));</p>
<p>return STATUS_SUCCESS; /* this doesn't actually happen */ }</p>
<p>注意从KiUserApcDispatcher()到NtContinue()并不是普通的函数调用，而是系统调用，这中间经历了空间的切换，也从用户空间堆栈切换到了系统空间堆栈。CPU进入系统调用空间后，在_KiSystemServicex下面的代码中把指向中断现场的框架指针保存在当前线程的 KTHREAD数据结构的TrapFrame字段中。这样，很容易就可以找到系统空间堆栈上的调用框架。当然，现在的框架是因为系统调用而产生的框架；而要想回到当初、即在执行用户空间APC函数之前的断点，就得先恢复当初的框架。那么当初的框架在哪里呢？它保存在用户空间的堆栈上，就是前面 KiInitializeUserApc()保存的CONTEXT数据结构中。所以，这里通过KeContextToTrapFrame()把当初保存的信息拷贝回来，从而恢复了当初的框架。<br>下面的KiContextToFxSaveArea()等语句与浮点处理器有关，我们在这里并不关心。<br>最后，汇编指令&#8220;jmp _KiServiceExit&#8221;使CPU跳转到了返回用户空间途中的_KiServiceExit处(见前面的代码)。在这里，CPU又会检查APC请求队列中是否有APC请求等着要执行，如果有的话又会进入KiDeliverApc()。前面讲过，每次进入KiDeliverApc()只会执行一个用户 APC请求，所以如果用户APC队列的长度大于1的话就得循环着多次走过上述的路线，即：<br>1. 从系统调用、中断、或异常返回途径_KiServiceExit，如果APC队列中有等待执行的APC请求，就调用KiDeliverApc()。<br>2. KiDeliverApc()，从用户APC队列中摘下一个APC请求。<br>3. 在KiInitializeUserApc()中保存当前框架，并伪造新的框架。<br>4. 回到用户空间。<br>5. 在KiUserApcDispatcher()中调用目标APC函数。<br>6. 通过系统调用NtContinue()进入系统空间。<br>7. 在NtContinue()中恢复当初保存的框架。<br>8. 从NtContinue()返回、途径_KiServiceExit时，如果APC队列中还有等待执行的APC请求，就调用KiDeliverApc()。于是转回上面的第二步。<br>这个过程一直要循环到APC队列中不再有需要执行的请求。注意这里每一次循环中保存和恢复的都是同一个框架，就是原始的、开始处理APC队列之前的那个框架，代表着原始的用户空间程序断点。一旦APC队列中不再有等待执行的APC请求，在_KiServiceExit下面就不再调用 KiDeliverApc()，于是就直接返回用户空间，这次是返回到原始的程序断点了。所以，系统调用neContinue()的作用不仅仅是切换回到被中断了的上下文，还包括执行用户APC队列中的下一个APC请求。<br>对于KiUserApcDispatcher()而言，它对NtContinue()的调用是不返回的。因为在NtContinue()中CPU不是&#8220;返回&#8221;到对于KiUserApcDispatcher()的另一次调用、从而对另一个APC函数的调用；就是返回到原始的用户空间程序断点，这个断点既可能是因为中断或异常而形成的，也可能是因为系统调用而形成的。</p>
<p>理解了常规的APC请求和执行机制，我们不妨再看看启动执行PE目标映像时函数的动态连接。以前讲过，PE格式EXE映像与(除ntdll.dll外的) DLL的动态连接、包括这些DLL的装入，是由ntdll.dll中的一个函数LdrInitializeThunk()作为APC函数执行而完成的，所以这也是对APC机制的一种变通使用。<br>要启动一个EXE映像运行时，首先要创建进程，再把目标EXE映像和ntdll.dll的映像都映射到新进程的用户空间，然后通过系统调用 NtCreateThread()创建这个进程的第一个线程、或称&#8220;主线程&#8221;。而LdrInitializeThunk()作为APC函数的执行，就是在 NtCreateThread()中安排好的。</p>
<p>&nbsp;</p>
<p>CODE:<br>NtCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess,<br>IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,<br>IN HANDLE ProcessHandle, OUT PCLIENT_ID ClientId,<br>IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb,<br>IN BOOLEAN CreateSuspended)<br>{<br>HANDLE hThread;</p>
<p>. . . . . .<br>. . . . . .<br>/*<br>* Queue an APC to the thread that will execute the ntdll startup<br>* routine.<br>*/ LdrInitApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));<br>KeInitializeApc(LdrInitApc, &amp;Thread-&gt;Tcb, OriginalApcEnvironment,<br>LdrInitApcKernelRoutine,<br>LdrInitApcRundownRoutine,<br>LdrpGetSystemDllEntryPoint(), UserMode, NULL);<br>KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);</p>
<p>/*<br>* The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE.<br>* We must do this manually. Do NOT attempt to set the Thread to Alertable before the call,<br>* doing so is a blatant and erronous hack.<br>*/ Thread-&gt;Tcb.ApcState.UserApcPending = TRUE;<br>Thread-&gt;Tcb.Alerted[KernelMode] = TRUE;<br>. . . . . .<br>. . . . . .<br>}</p>
<p>NeCreateThread ()要做的事当然很多，但是其中很重要的一项就是安排好APC函数的执行。这里的KeInitializeApc()和KeInsertQueueApc 读者都已经熟悉了，所以我们只关心调用参数中的三个函数指针，特别是其中的KernelRoutine和NormalRoutine。前者十分简单：</p>
<p>&nbsp;</p>
<p>CODE:<br>VOID STDCALL<br>LdrInitApcKernelRoutine(PKAPC Apc, PKNORMAL_ROUTINE* NormalRoutine,<br>PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2)<br>{<br>ExFreePool(Apc);<br>}</p>
<p>而NormalRoutine，这里是通过LdrpGetSystemDllEntryPoint()获取的，它只是返回全局量SystemDllEntryPoint的值：</p>
<p>&nbsp;</p>
<p>CODE:<br>PVOID LdrpGetSystemDllEntryPoint(VOID)<br>{<br>return(SystemDllEntryPoint);<br>}</p>
<p>前面已经讲到，全局量SystemDllEntryPoint是在LdrpMapSystemDll()时得到设置的，指向已经映射到用户空间的 ntdll.dll映像中的LdrInitializeThunk()。注意这APC请求是挂在新线程的队列中，而不是当前进程的队列中。事实上，新线程和当前进程处于不同的进程，因而不在同一个用户空间中。还要注意，这里的NormalRoutine直接就是LdrInitializeThunk()，而不像前面通过QueueUserAPC()发出的APC请求那样中间还有一层IntCallUserApc()。至于 KiUserApcDispatcher()，那是由KeInitializeApc()强制加上的，正是这个函数保证了对NtContinue()的调用。<br>此后的流程本来无需细说了，但是由于情景的特殊性还是需要加一些简要的说明。由NtCreateProcess()创建的进程并非一个可以调度运行的实体，而NtCreateThread()创建的线程却是。所以，在NtCreateProcess()返回的前夕，系统中已经多了一个线程。这个新增线程的&#8220;框架&#8221;是伪造的，目的在于让这个线程一开始在用户空间运行就进入预定的程序入口。从NtCreateProcess()返回是回到当前线程、而不是新增线程，而刚才的APC请求是挂在新增线程的队列中，所以在从NtCreateThread()返回的途中不会去执行这个APC请求。可是，当新增线程受调度运行时，首先就是按伪造的框架和堆栈模拟一个从系统调用返回的过程，所以也要途径_KiServiceExit。这时候，这个APC请求就要得到执行了(由KiUserApcDispatcher()调用LdrInitializeThunk())。然后，在用户空间执行完APC函数 LdrInitializeThunk()以后，同样也是通过NtContinue()回到内核中，然后又按原先的伪造框架&#8220;返回&#8221;到用户空间，这才真正开始了新线程在用户空间的执行。</p>
<p>最后，我们不妨比较一下APC机制和Unix/Linux的Signal机制。<br>Unix/Linux的Signal机制基本上是对硬件中断机制的软件模拟，具体表现在以下几个方面：<br>1） 现代的硬件中断机制一般都是&#8220;向量中断&#8221;机制，而Signal机制中的Signal序号(例如SIG_KILL)就是对中断向量序号的模拟。<br>2）作为操作系统对硬件中断机制的支持，一般都会提供&#8220;设置中断向量&#8221;一类的内核函数，使特定序号的中断向量指向某个中断服务程序。而系统调用signal ()就相当于是这一类的函数。只不过前者在内核中、一般只是供其它内核函数调用，而后者是系统调用、供用户空间的程序调用。<br>3）在硬件中断机制中，&#8220;中断向量&#8221;的设置只是为某类异步事件、及中断的发生做好了准备，但是并不意味着某个特定时间的发生。如果一直没有中断请求，那么所设置的中断向量就一直得不到执行，而中断的发生只是触发了中断服务程序的执行。在Signal机制中，向某个进程发出&#8220;信号&#8221;、即Signal、就相当于中断请求。<br>相比之下，APC机制就不能说是对于硬件中断机制的模拟了。首先，通过NtQueueApcThread()设置一个APC函数跟通过signal()设置一个&#8220;中断向量&#8221;有所不同。将一个APC函数挂入APC队列中时，对于这个函数的得到执行、以及大约在什么时候得到执行，实际上是预知的，只是这得到执行的条件要过一回儿才会成熟。而&#8220;中断&#8221;则不同，中断向量的设置只是说如果发生某种中断则如何如何，但是对于其究竟是否会发生、何时发生则常常是无法预测的。所以，从这个意义上说，APC函数只是一种推迟执行、异步执行的函数调用，因此称之为&#8220;异步过程调用&#8221;确实更为贴切。<br>还有，signal机制的signal()所设置的&#8220;中断服务程序&#8221;都是用户空间的程序，而APC机制中挂入APC队列的函数却可以是内核函数。<br>但是，尽管如此，它们的(某些方面的)实质还是一样的。&#8220;中断&#8221;本来就是一种异步执行的机制。再说，(用户)APC与Signal的执行流程几乎完全一样，都是在从内核返回用户空间的前夕检查是否有这样的函数需要加以执行，如果是就临时修改堆栈，偏离原来的执行路线，使得返回用户空间后进入APC函数，并且在执行完了这个函数以后仍进入内核，然后恢复原来的堆栈，再次返回用户空间原来的断点。这样，对于原来的流程而言，就相当于受到了中断。</p><img src ="http://www.cppblog.com/momoxiao/aggbug/109992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-03-18 15:09 <a href="http://www.cppblog.com/momoxiao/archive/2010/03/18/109992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows驱动程序加载</title><link>http://www.cppblog.com/momoxiao/archive/2010/03/12/109557.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 12 Mar 2010 11:55:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/03/12/109557.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/109557.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/03/12/109557.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/109557.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/109557.html</trackback:ping><description><![CDATA[总线驱动器的任务之一就是枚举总线上的设备。并为每个设备创建一个PDO。一旦总线驱动器程序检查到新硬件存在，PnP管理器就创建一个PDO，创建完PDO后，PnP管理器<strong>参照注册表中的信息查找与这个PDO相关的过滤器和功能驱动程序</strong>。系统安装程序负责这些注册表项，而驱动程序包中控制硬件安装的INF文件负责添加其他表项。这些表项定义了过滤器和功能驱动程序在堆栈中的次序。<br>--------------------------------------------<br>1.创建设备 <br>设备创建一般在设备管理器发现新设备时进行：设备管理器通过读取驱动程序inf文件来创建新设备，将这个设备注册为特定的设备接口并建立符号链接，这样使操作系统能正确识别这个硬件。在驱动程序安装过程中，设备管理器还会根据inf文件将驱动程序拷贝到系统目录，并通过写入相关注册表信息建立服务，使这个驱动程序能够在系统启动时被自动加载。 <br><br>2.硬件资源分配<br>&nbsp;驱动程序需要知道为它们分配了那些硬件资源。常见的硬件资源有I/O端口、存储器地址、中断和DMA。我们可通过设备管理器中的"资源"选项来查看某个设备的资源分配情况，这些工作都是由系统自动完成的。当然，如果这个设备的资源与其他设备的资源相冲突将不能正常工作，这时候必须通过设备管理器来手动配置资源。 <br><br>3.串行化处理 <br>在多处理器系统中，处理程序可同时在两个不同的处理器上运行，但如果它们都试图访问同一硬件时，则会出现不可预料的结果。WDM驱动重要的功能之一就是提供一个机制，保证驱动程序的不同部分不会同时访问相同的硬件，避免设备发生冲突。 <br><br>4.访问硬件 <br>驱动程序在取得了I/O端口和内存地址后就可以直接访问硬件，但由于Windows是多任务操作系统，在一般情况下占用处理器的时间应小于50微秒，如果需要长时间的硬件访问应采用系统线程的方法。 <br><br>5.即插即用支持 <br>即插即用（PnP）是系统自动识别和适应硬件配置改变的技术。即插即用不仅需要硬件支持同时还需要软件支持。驱动程序是对即插即用支持很重要的部分，用户可随时为计算机添加和删除设备而无需进行手工配置。微软作为PnP规范的制定者已经定义了相关设备和组件的工业标准，通过这些标准我们可以了解操作系统和驱动程序如何支持即插即用。操作系统和驱动程序对即插即用的支持主要提供的功能有自动识别已安装的设备；硬件资源的动态分配；自动加载正确的驱动程序；在硬件环境发生变化时，向驱动程序发出通知。 <br><br>6.电源管理支持 <br>电源管理也需要软硬件同时支持，支持PnP的驱动程序必须支持电源管理，反之亦然。WDM驱动程序和操作系统共同管理设备电源，维持系统的电源消耗并节约电量的使用。Windows 98和Windows 2000以及其他支持电源管理的操作系统中，计算机和其他外设被维持在可能的最低电源使用水平上来完成当前工作，这在移动PC和笔记本电脑上显得尤为重要。&nbsp;&nbsp;&nbsp;&nbsp;<img src ="http://www.cppblog.com/momoxiao/aggbug/109557.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-03-12 19:55 <a href="http://www.cppblog.com/momoxiao/archive/2010/03/12/109557.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NextLuRequest for scsi miniport driver</title><link>http://www.cppblog.com/momoxiao/archive/2010/03/05/108929.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Mar 2010 01:35:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/03/05/108929.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/108929.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/03/05/108929.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/108929.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/108929.html</trackback:ping><description><![CDATA[<a href="http://www.osronline.com/showthread.cfm?link=149287">http://www.osronline.com/showthread.cfm?link=149287</a><br><img src ="http://www.cppblog.com/momoxiao/aggbug/108929.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-03-05 09:35 <a href="http://www.cppblog.com/momoxiao/archive/2010/03/05/108929.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windbg dump 内存映象</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/27/108531.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Sat, 27 Feb 2010 03:49:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/27/108531.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/108531.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/27/108531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/108531.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/108531.html</trackback:ping><description><![CDATA[.writemem命令<br><br>dump&nbsp;0x8048000开始的19870字节到C:\FileName.dat<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #000000;">.writemem&nbsp;C:\FileName.dat&nbsp;</span><span style="color: #000000;">8048000</span><span style="color: #000000;">&nbsp;L0n19870</span></div><img src ="http://www.cppblog.com/momoxiao/aggbug/108531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-27 11:49 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/27/108531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GetLastError()返回值的意义zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/25/108424.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Thu, 25 Feb 2010 06:02:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/25/108424.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/108424.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/25/108424.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/108424.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/108424.html</trackback:ping><description><![CDATA[〖0〗-操作成功完成。<br>〖1〗-功能错误。<br>〖2〗-系统找不到指定的文件。<br>〖3〗-系统找不到指定的路径。<br>〖4〗-系统无法打开文件。<br>〖5〗-拒绝访问。<br>〖6〗-句柄无效。<br>〖7〗-存储控制块被损坏。<br>〖8〗-存储空间不足，无法处理此命令。<br>〖9〗-存储控制块地址无效。<br>〖10〗-环境错误。<br>〖11〗-试图加载格式错误的程序。<br>〖12〗-访问码无效。<br>〖13〗-数据无效。<br>〖14〗-存储器不足，无法完成此操作。<br>〖15〗-系统找不到指定的驱动器。<br>〖16〗-无法删除目录。<br>〖17〗-系统无法将文件移到不同的驱动器。<br>〖18〗-没有更多文件。<br>〖19〗-介质受写入保护。<br>〖20〗-系统找不到指定的设备。 <br>〖21〗-设备未就绪。 <br>〖22〗-设备不识别此命令。 <br>〖23〗-数据错误 (循环冗余检查)。 <br>〖24〗-程序发出命令，但命令长度不正确。 <br>〖25〗-驱动器无法找出磁盘上特定区域或磁道的位置。 <br>〖26〗-无法访问指定的磁盘或软盘。 <br>〖27〗-驱动器找不到请求的扇区。 <br>〖28〗-打印机缺纸。 <br>〖29〗-系统无法写入指定的设备。 <br>〖30〗-系统无法从指定的设备上读取。 <br>〖31〗-连到系统上的设备没有发挥作用。 <br>〖32〗-进程无法访问文件，因为另一个程序正在使用此文件。 <br>〖33〗-进程无法访问文件，因为另一个程序已锁定文件的一部分。 <br>〖36〗-用来共享的打开文件过多。 <br>〖38〗-到达文件结尾。 <br>〖39〗-磁盘已满。 <br>〖50〗-不支持网络请求。 <br>〖51〗-远程计算机不可用 。 <br>〖52〗-在网络上已有重复的名称。 <br>〖53〗-找不到网络路径。 <br>〖54〗-网络忙。 <br>〖55〗-指定的网络资源或设备不再可用。 <br>〖56〗-已到达网络 BIOS 命令限制。 <br>〖57〗-网络适配器硬件出错。 <br>〖58〗-指定的服务器无法运行请求的操作。 <br>〖59〗-发生意外的网络错误。 <br>〖60〗-远程适配器不兼容。 <br>〖61〗-打印机队列已满。 <br>〖62〗-无法在服务器上获得用于保存待打印文件的空间。 <br>〖63〗-删除等候打印的文件。 <br>〖64〗-指定的网络名不再可用。 <br>〖65〗-拒绝网络访问。 <br>〖66〗-网络资源类型错误。 <br>〖67〗-找不到网络名。 <br>〖68〗-超过本地计算机网卡的名称限制。 <br>〖69〗-超出网络 BIOS 会话限制。 <br>〖70〗-远程服务器已暂停，或正在启动过程中。 <br>〖71〗-当前已无法再同此远程计算机连接，因为已达到计算机的连接数目极限。 <br>〖72〗-已暂停指定的打印机或磁盘设备。 <br>〖80〗-文件存在。 <br>〖82〗-无法创建目录或文件。 <br>〖83〗-INT 24 失败。 <br>〖84〗-无法取得处理此请求的存储空间。 <br>〖85〗-本地设备名已在使用中。 <br>〖86〗-指定的网络密码错误。 <br>〖87〗-参数错误。 <br>〖88〗-网络上发生写入错误。 <br>〖89〗-系统无法在此时启动另一个进程。 <br>〖100〗-无法创建另一个系统信号灯。 <br>〖101〗-另一个进程拥有独占的信号灯。 <br>〖102〗-已设置信号灯且无法关闭。 <br>〖103〗-无法再设置信号灯。 <br>〖104〗-无法在中断时请求独占的信号灯。 <br>〖105〗-此信号灯的前一个所有权已结束。 <br>〖107〗-程序停止，因为替代的软盘未插入。 <br>〖108〗-磁盘在使用中，或被另一个进程锁定。 <br>〖109〗-管道已结束。 <br>〖110〗-系统无法打开指定的设备或文件。 <br>〖111〗-文件名太长。 <br>〖112〗-磁盘空间不足。 <br>〖113〗-无法再获得内部文件的标识。 <br>〖114〗-目标内部文件的标识不正确。 <br>〖117〗-应用程序制作的 IOCTL 调用错误。 <br>〖118〗-验证写入的切换参数值错误。 <br>〖119〗-系统不支持请求的命令。 <br>〖120〗-此功能只被此系统支持。 <br>〖121〗-信号灯超时时间已到。 <br>〖122〗-传递到系统调用的数据区太小。 <br>〖123〗-文件名、目录名或卷标语法不正确。 <br>〖124〗-系统调用级别错误。 <br>〖125〗-磁盘没有卷标。 <br>〖126〗-找不到指定的模块。 <br>〖127〗-找不到指定的程序。 <br>〖128〗-没有等候的子进程。 <br>〖130〗-试图使用操作(而非原始磁盘 I/O)的已打开磁盘分区的文件句柄。 <br>〖131〗-试图移动文件指针到文件开头之前。 <br>〖132〗-无法在指定的设备或文件上设置文件指针。 <br>〖133〗-包含先前加入驱动器的驱动器无法使用 JOIN 或 SUBST 命令。 <br>〖134〗-试图在已被合并的驱动器上使用 JOIN 或 SUBST 命令。 <br>〖135〗-试图在已被合并的驱动器上使用 JOIN 或 SUBST 命令。 <br>〖136〗-系统试图解除未合并驱动器的 JOIN。 <br>〖137〗-系统试图解除未替代驱动器的 SUBST。 <br>〖138〗-系统试图将驱动器合并到合并驱动器上的目录。 <br>〖139〗-系统试图将驱动器替代为替代驱动器上的目录。 <br>〖140〗-系统试图将驱动器合并到替代驱动器上的目录。 <br>〖141〗-系统试图替代驱动器为合并驱动器上的目录。 <br>〖142〗-系统无法在此时运行 JOIN 或 SUBST。 <br>〖143〗-系统无法将驱动器合并到或替代为相同驱动器上的目录。 <br>〖144〗-目录并非根目录下的子目录。 <br>〖145〗-目录非空。 <br>〖146〗-指定的路径已在替代中使用。 <br>〖147〗-资源不足，无法处理此命令。 <br>〖148〗-指定的路径无法在此时使用。 <br>〖149〗-企图将驱动器合并或替代为驱动器上目录是上一个替代的目标的驱动器。 <br>〖150〗-系统跟踪信息未在 CONFIG.SYS 文件中指定，或不允许跟踪。 <br>〖151〗-为 DosMuxSemWait 指定的信号灯事件个数错误。 <br>〖152〗-DosMuxSemWait 不可运行。已设置过多的信号灯。 <br>〖153〗-DosMuxSemWait 清单错误。 <br>〖154〗-输入的卷标超过目标文件系统的长度限制 <br>〖155〗-无法创建另一个线程。 <br>〖156〗-接收进程已拒绝此信号。 <br>〖157〗-段已被放弃且无法锁定。 <br>〖158〗-段已解除锁定。 <br>〖159〗-线程标识的地址错误。 <br>〖160〗-传递到 DosExecPgm 的参数字符串错误。 <br>〖161〗-指定的路径无效。 <br>〖162〗-信号已暂停。 <br>〖164〗-无法在系统中创建更多的线程。 <br>〖167〗-无法锁定文件区域。 <br>〖170〗-请求的资源在使用中。 <br>〖173〗-对于提供取消区域进行锁定的请求不明显。 <br>〖174〗-文件系统不支持锁定类型的最小单元更改。 <br>〖180〗-系统检测出错误的段号。 <br>〖183〗-当文件已存在时，无法创建该文件。 <br>〖186〗-传递的标志错误。 <br>〖187〗-找不到指定的系统信号灯名称。 <br>〖196〗-操作系统无法运行此应用程序。 <br>〖197〗-操作系统当前的配置不能运行此应用程序。 <br>〖199〗-操作系统无法运行此应用程序。 <br>〖200〗-代码段不可大于或等于 64K。 <br>〖203〗-操作系统找不到已输入的环境选项。 <br>〖205〗-命令子树中的进程没有信号处理程序。 <br>〖206〗-文件名或扩展名太长。 <br>〖207〗-第 2 环堆栈已被占用。 <br>〖208〗-没有正确输入文件名通配符 * 或 ?，或指定过多的文件名通配符。 <br>〖209〗-正在发送的信号错误。 <br>〖210〗-无法设置信号处理程序。 <br>〖212〗-段已锁定且无法重新分配。 <br>〖214〗-连到该程序或动态链接模块的动态链接模块太多。 <br>〖215〗-无法嵌套调用 LoadModule。 <br>〖230〗-管道状态无效。 <br>〖231〗-所有的管道实例都在使用中。 <br>〖232〗-管道正在关闭中。 <br>〖233〗-管道的另一端上无任何进程。 <br>〖234〗-更多数据可用。 <br>〖240〗-取消会话。 <br>〖254〗-指定的扩展属性名无效。 <br>〖255〗-扩展属性不一致。 <br>〖258〗-等待的操作过时。 <br>〖259〗-没有可用的数据了。 <br>〖266〗-无法使用复制功能。 <br>〖267〗-目录名无效。 <br>〖275〗-扩展属性在缓冲区中不适用。 <br>〖276〗-装在文件系统上的扩展属性文件已损坏。 <br>〖277〗-扩展属性表格文件已满。 <br>〖278〗-指定的扩展属性句柄无效。 <br>〖282〗-装入的文件系统不支持扩展属性。 <br>〖288〗-企图释放并非呼叫方所拥有的多用户终端运行程序。 <br>〖298〗-发向信号灯的请求过多。 <br>〖299〗-仅完成部分的 ReadProcessMemoty 或 WriteProcessMemory 请求。 <br>〖300〗-操作锁定请求被拒绝。 <br>〖301〗-系统接收了一个无效的操作锁定确认。 <br>〖487〗-试图访问无效的地址。 <br>〖534〗-算术结果超过 32 位。 <br>〖535〗-管道的另一端有一进程。 <br>〖536〗-等候打开管道另一端的进程。 <br>〖994〗-拒绝访问扩展属性。 <br>〖995〗-由于线程退出或应用程序请求，已放弃 I/O 操作。 <br>〖996〗-重叠 I/O 事件不在信号状态中。 <br>〖997〗-重叠 I/O 操作在进行中。 <br>〖998〗-内存分配访问无效。 <br>〖999〗-错误运行页内操作。&nbsp;&nbsp;<br>〖1001〗-递归太深；栈溢出。 <br>〖1002〗-窗口无法在已发送的消息上操作。 <br>〖1003〗-无法完成此功能。 <br>〖1004〗-无效标志。 <br>〖1005〗-此卷不包含可识别的文件系统。请确定所有请求的文件系统驱动程序已加载，且此卷未损坏。 <br>〖1006〗-文件所在的卷已被外部改变，因此打开的文件不再有效。 <br>〖1007〗-无法在全屏幕模式下运行请求的操作。 <br>〖1008〗-试图引用不存在的令牌。 <br>〖1009〗-配置注册表数据库损坏。 <br>〖1010〗-配置注册表项无效。 <br>〖1011〗-无法打开配置注册表项。 <br>〖1012〗-无法读取配置注册表项。 <br>〖1013〗-无法写入配置注册表项。 <br>〖1014〗-注册表数据库中的某一文件必须使用记录或替代复制来恢复。恢复成功完成。 <br>〖1015〗-注册表损坏。包含注册表数据的某一文件结构损坏，或系统的文件内存映像损坏，或因为替代副本、日志缺少或损坏而无法恢复文件。 <br>〖1016〗-由注册表启动的 I/O 操作恢复失败。注册表无法读入、写出或清除任意一个包含注册表系统映像的文件。 <br>〖1017〗-系统试图加载或还原文件到注册表，但指定的文件并非注册表文件格式。 <br>〖1018〗-试图在标记为删除的注册表项上运行不合法的操作。 <br>〖1019〗-系统无法配置注册表日志中所请求的空间。 <br>〖1020〗-无法在已有子项或值的注册表项中创建符号链接。 <br>〖1021〗-无法在易变父项下创建稳定子项。 <br>〖1022〗-通知更改请求正在完成中，且信息并未返回到呼叫方的缓冲区中。当前呼叫方必须枚举文件来查找更改。 <br>〖1051〗-已发送停止控制到服务，该服务被其它正在运行的服务所依赖。 <br>〖1052〗-请求的控件对此服务无效 <br>〖1053〗-服务并未及时响应启动或控制请求。 <br>〖1054〗-无法创建此服务的线程。 <br>〖1055〗-锁定服务数据库。 <br>〖1056〗-服务的实例已在运行中。 <br>〖1057〗-帐户名无效或不存在，或者密码对于指定的帐户名无效。 <br>〖1058〗-无法启动服务，原因可能是它被禁用或与它相关联的设备没有启动。 <br>〖1059〗-指定了循环服务依存。 <br>〖1060〗-指定的服务并未以已安装的服务存在。 <br>〖1061〗-服务无法在此时接受控制信息。 <br>〖1062〗-服务未启动。 <br>〖1063〗-服务进程无法连接到服务控制器上。 <br>〖1064〗-当处理控制请求时，在服务中发生异常。 <br>〖1065〗-指定的数据库不存在。 <br>〖1066〗-服务已返回特定的服务错误码。 <br>〖1067〗-进程意外终止。 <br>〖1068〗-依存服务或组无法启动。 <br>〖1069〗-由于登录失败而无法启动服务。 <br>〖1070〗-启动后，服务停留在启动暂停状态。 <br>〖1071〗-指定的服务数据库锁定无效。 <br>〖1072〗-指定的服务已标记为删除。 <br>〖1073〗-指定的服务已存在。 <br>〖1074〗-系统当前以最新的有效配置运行。 <br>〖1075〗-依存服务不存在，或已被标记为删除。 <br>〖1076〗-已接受使用当前引导作为最后的有效控制设置。 <br>〖1077〗-上次启动之后，仍未尝试引导服务。 <br>〖1078〗-名称已用作服务名或服务显示名。 <br>〖1079〗-此服务的帐户不同于运行于同一进程上的其它服务的帐户。 <br>〖1080〗-只能为 Win32 服务设置失败操作，不能为驱动程序设置。 <br>〖1081〗-这个服务所运行的处理和服务控制管理器相同。所以，如果服务处理程序意外中止的话，服务控制管理器无法进行任何操作。 <br>〖1082〗-这个服务尚未设置恢复程序。 <br>〖1083〗-配置成在该可执行程序中运行的这个服务不能执行该服务。 <br>〖1100〗-已达磁带的实际结尾。 <br>〖1101〗-磁带访问已达文件标记。 <br>〖1102〗-已达磁带或磁盘分区的开头。 <br>〖1103〗-磁带访问已达一组文件的结尾。 <br>〖1104〗-磁带上不再有任何数据。 <br>〖1105〗-磁带无法分区。 <br>〖1106〗-在访问多卷分区的新磁带时，当前的块大小不正确。 <br>〖1107〗-当加载磁带时，找不到分区信息。 <br>〖1108〗-无法锁定媒体弹出功能。 <br>〖1109〗-无法卸载介质。 <br>〖1110〗-驱动器中的介质可能已更改。 <br>〖1111〗-复位 I/O 总线。 <br>〖1112〗-驱动器中没有媒体。 <br>〖1113〗-在多字节的目标代码页中，没有此 Unicode 字符可以映射到的字符。 <br>〖1114〗-动态链接库 (DLL) 初始化例程失败。 <br>〖1115〗-系统关机正在进行。 <br>〖1116〗-因为没有任何进行中的关机过程，所以无法中断系统关机。 <br>〖1117〗-因为 I/O 设备错误，所以无法运行此项请求。 <br>〖1118〗-没有串行设备被初始化成功。串行驱动程序将卸载。 <br>〖1119〗-无法打开正在与其他设备共享中断请求(IRQ)的设备。至少有一个使用该 IRQ 的其他设备已打开。 <br>〖1120〗-序列 I/O 操作已由另一个串行口的写入完成。(IOCTL_SERIAL_XOFF_COUNTER 已达零。) <br>〖1121〗-因为已过超时时间，所以串行 I/O 操作完成。(IOCTL_SERIAL_XOFF_COUNTER 未达零。) <br>〖1122〗-在软盘上找不到 ID 地址标记。 <br>〖1123〗-软盘扇区 ID 字符域与软盘控制器磁道地址不相符。 <br>〖1124〗-软盘控制器报告软盘驱动程序不能识别的错误。 <br>〖1125〗-软盘控制器返回与其寄存器中不一致的结果。 <br>〖1126〗-当访问硬盘时，重新校准操作失败，重试仍然失败。 <br>〖1127〗-当访问硬盘时，磁盘操作失败，重试仍然失败。 <br>〖1128〗-当访问硬盘时，即使失败，仍须复位磁盘控制器。 <br>〖1129〗-已达磁带结尾。 <br>〖1130〗-服务器存储空间不足，无法处理此命令。 <br>〖1131〗-检测出潜在的死锁状态。 <br>〖1132〗-指定的基址或文件偏移量没有适当对齐。 <br>〖1140〗-改变系统供电状态的尝试被另一应用程序或驱动程序否决。 <br>〖1141〗-系统 BIOS 改变系统供电状态的尝试失败。 <br>〖1142〗-试图在一文件上创建超过系统允许数额的链接。 <br>〖1150〗-指定程序要求更新的 Windows 版本。 <br>〖1151〗-指定程序不是 Windows 或 MS-DOS 程序。 <br>〖1152〗-只能启动该指定程序的一个实例。 <br>〖1153〗-该指定程序适用于旧的 Windows 版本。 <br>〖1154〗-执行该应用程序所需的库文件之一被损坏。 <br>〖1155〗-没有应用程序与此操作的指定文件有关联。 <br>〖1156〗-在输送指令到应用程序的过程中出现错误。　 <br>〖1157〗-执行该应用程序所需的库文件之一无法找到。 <br>〖1158〗-当前程序已使用了 Window 管理器对象的系统允许的所有句柄。 <br>〖1159〗-消息只能与同步操作一起使用。 <br>〖1160〗-指出的源元素没有媒体。 <br>〖1161〗-指出的目标元素已包含媒体。 <br>〖1162〗-指出的元素不存在。 <br>〖1163〗-指出的元素是未显示的存储资源的一部分。 <br>〖1164〗-显示设备需要重新初始化，因为硬件有错误。 <br>〖1165〗-设备显示在尝试进一步操作之前需要清除。 <br>〖1166〗-设备显示它的门仍是打开状态。 <br>〖1167〗-设备没有连接。 <br>〖1168〗-找不到元素。 <br>〖1169〗-索引中没有同指定项相匹配的项。 <br>〖1170〗-在对象上不存在指定的属性集。 <br>〖1171〗-传递到 GetMouseMovePoints 的点不在缓冲区中。 <br>〖1172〗-跟踪(工作站)服务没运行。 <br>〖1173〗-找不到卷 ID。 <br>〖1175〗-无法删除要被替换的文件。 <br>〖1176〗-无法将替换文件移到要被替换的文件。要被替换的文件保持原来的名称。 <br>〖1177〗-无法将替换文件移到要被替换的文件。要被替换的文件已被重新命名为备份名称。 <br>〖1178〗-卷更改记录被删除。 <br>〖1179〗-卷更改记录服务不处于活动中。 <br>〖1180〗-找到一份文件，但是可能不是正确的文件。 <br>〖1181〗-日志项从日志中被删除。 <br>〖1200〗-指定的设备名无效。 <br>〖1201〗-设备当前未连接上，但其为一个记录连接。 <br>〖1202〗-企图记录先前已被记录的设备。 <br>〖1203〗-无任何网络提供程序接受指定的网络路径。 <br>〖1204〗-指定的网络提供程序名称无效。 <br>〖1205〗-无法打开网络连接配置文件。 <br>〖1206〗-网络连接配置文件损坏。 <br>〖1207〗-无法枚举空载体。 <br>〖1208〗-发生扩展错误。 <br>〖1209〗-指定的组名格式无效。 <br>〖1210〗-指定的计算机名格式无效。 <br>〖1211〗-指定的事件名格式无效。 <br>〖1212〗-指定的域名格式无效。 <br>〖1213〗-指定的服务名格式无效。 <br>〖1214〗-指定的网络名格式无效。 <br>〖1215〗-指定的共享名格式无效。 <br>〖1216〗-指定的密码格式无效。 <br>〖1217〗-指定的消息名格式无效。 <br>〖1218〗-指定的消息目标格式无效。 <br>〖1219〗-提供的凭据与已存在的凭据集冲突。 <br>〖1220〗-企图创建网络服务器的会话，但已对该服务器创建过多的会话。 <br>〖1221〗-工作组或域名已由网络上的另一部计算机使用。 <br>〖1222〗-网络未连接或启动。 <br>〖1223〗-操作已被用户取消。 <br>〖1224〗-请求的操作无法在使用用户映射区域打开的文件上执行。 <br>〖1225〗-远程系统拒绝网络连接。 <br>〖1226〗-网络连接已被适当地关闭了。 <br>〖1227〗-网络传输终结点已有与其关联的地址。 <br>〖1228〗-地址仍未与网络终结点关联。 <br>〖1229〗-企图在不存在的网络连接上进行操作。 <br>〖1230〗-企图在使用中的网络连接上进行无效的操作。 <br>〖1231〗-不能访问网络位置。有关网络排除故障的信息，请参阅 Windows 帮助。 <br>〖1232〗-不能访问网络位置。有关网络排除故障的信息，请参阅 Windows 帮助。 <br>〖1233〗-不能访问网络位置。有关网络排除故障的信息，请参阅 Windows 帮助。 <br>〖1234〗-没有任何服务正在远程系统上的目标网络终结点上操作。 <br>〖1235〗-请求被终止。 <br>〖1236〗-由本地系统终止网络连接。 <br>〖1237〗-操作无法完成。应该重试。 <br>〖1238〗-因为已达到此帐户的最大同时连接数限制，所以无法连接服务器。 <br>〖1239〗-试图在这个帐户未被授权的时间内登录。 <br>〖1240〗-此帐户并未得到从这个工作站登录的授权。 <br>〖1241〗-请求的操作不能使用这个网络地址。 <br>〖1242〗-服务器已经注册。 <br>〖1243〗-指定的服务不存在。 <br>〖1244〗-因为用户还未被验证，不能执行所要求的操作。 <br>〖1245〗-因为用户还未登录网络，不能执行所要求的操作。指定的服务不存在。 <br>〖1246〗-正在继续工作。 <br>〖1247〗-试图进行初始操作，但是初始化已完成。 <br>〖1248〗-没有更多的本地设备。　 <br>〖1249〗-指定的站点不存在。 <br>〖1250〗-具有指定名称的域控制器已经存在。 <br>〖1251〗-只有连接到服务器上时，该操作才受支持。 <br>〖1252〗-即使没有改动，组策略框架也应该调用扩展。 <br>〖1253〗-指定的用户没有一个有效的配置文件。 <br>〖1254〗-Microsoft Small Business Server 不支持此操作。 <br>〖1300〗-并非所有被引用的特权都指派给呼叫方。 <br>〖1301〗-帐户名和安全标识间的某些映射未完成。 <br>〖1302〗-没有为该帐户特别设置系统配额限制。 <br>〖1303〗-没有可用的加密密钥。返回了一个已知加密密钥。 <br>〖1304〗-密码太复杂，无法转换成 LAN Manager 密码。返回的 LAN Manager 密码为空字符串。 <br>〖1305〗-修订级别未知。 <br>〖1306〗-表明两个修订级别是不兼容的。 <br>〖1307〗-这个安全标识不能指派为此对象的所有者。 <br>〖1308〗-这个安全标识不能指派为对象的主要组。 <br>〖1309〗-当前并未模拟客户的线程试图操作模拟令牌。 <br>〖1310〗-组可能未被禁用。 <br>〖1311〗-当前没有可用的登录服务器来服务登录请求。 <br>〖1312〗-指定的登录会话不存在。可能已被终止。 <br>〖1313〗-指定的特权不存在。 <br>〖1314〗-客户没有所需的特权。 <br>〖1315〗-提供的名称并非正确的帐户名形式。 <br>〖1316〗-指定的用户已存在。 <br>〖1317〗-指定的用户不存在。 <br>〖1318〗-指定的组已存在。 <br>〖1319〗-指定的组不存在。 <br>〖1320〗-指定的用户帐户已是指定组的成员，或是因为组包含成员所以无法删除指定的组。 <br>〖1321〗-指定的用户帐户不是指定组帐户的成员。 <br>〖1322〗-无法禁用或删除最后剩余的系统管理帐户。 <br>〖1323〗-无法更新密码。提供作为当前密码的值不正确。 <br>〖1324〗-无法更新密码。提供给新密码的值包含密码中不允许的值。 <br>〖1325〗-无法更新密码。为新密码提供的值不符合字符域的长度、复杂性或历史要求。 <br>〖1326〗-登录失败: 未知的用户名或错误密码。 <br>〖1327〗-登录失败: 用户帐户限制。 <br>〖1328〗-登录失败: 违反帐户登录时间限制。 <br>〖1329〗-登录失败: 不允许用户登录到此计算机。 <br>〖1330〗-登录失败: 指定的帐户密码已过期。 <br>〖1331〗-登录失败: 禁用当前的帐户。 <br>〖1332〗-帐户名与安全标识间无任何映射完成。 <br>〖1333〗-一次请求过多的本地用户标识符(LUIDs)。 <br>〖1334〗-无更多可用的本地用户标识符(LUIDs)。 <br>〖1335〗-对于该特别用法，安全 ID 的次级授权部分无效。 <br>〖1336〗-访问控制列表(ACL)结构无效。 <br>〖1337〗-安全 ID 结构无效。 <br>〖1338〗-安全描述符结构无效。 <br>〖1340〗-无法创建固有的访问控制列表(ACL)或访问控制项目(ACE)。 <br>〖1341〗-服务器当前已禁用。 <br>〖1342〗-服务器当前已启用。 <br>〖1343〗-提供给识别代号颁发机构的值为无效值。 <br>〖1344〗-无更多可用的内存以更新安全信息。 <br>〖1345〗-指定属性无效，或与整个群体的属性不兼容。 <br>〖1346〗-指定的模拟级别无效， 或所提供的模拟级别无效。 <br>〖1347〗-无法打开匿名级安全令牌。 <br>〖1348〗-请求的验证信息类别无效。 <br>〖1349〗-令牌的类型对其尝试使用的方法不适当。 <br>〖1350〗-无法在与安全性无关联的对象上运行安全性操作。 <br>〖1351〗-未能从域控制器读取配置信息，或者是因为机器不可使用，或者是访问被拒绝。 <br>〖1352〗-安全帐户管理器(SAM)或本地安全颁发机构(LSA)服务器处于运行安全操作的错误状态。 <br>〖1353〗-域处于运行安全操作的错误状态。 <br>〖1354〗-此操作只对域的主要域控制器可行。 <br>〖1355〗-指定的域不存在，或无法联系。 <br>〖1356〗-指定的域已存在。 <br>〖1357〗-试图超出每服务器域个数的限制。 <br>〖1358〗-无法完成请求操作，因为磁盘上的严重介质失败或数据结构损坏。 <br>〖1359〗-出现了内部错误。 <br>〖1360〗-通用访问类型包含于已映射到非通用类型的访问掩码中。 <br>〖1361〗-安全描述符格式不正确 (绝对或自相关的)。 <br>〖1362〗-请求操作只限制在登录进程中使用。调用进程未注册为一个登录进程。 <br>〖1363〗-无法使用已在使用中的标识启动新的会话。 <br>〖1364〗-未知的指定验证数据包。 <br>〖1365〗-登录会话并非处于与请求操作一致的状态中。 <br>〖1366〗-登录会话标识已在使用中。 <br>〖1367〗-登录请求包含无效的登录类型值。 <br>〖1368〗-在使用命名管道读取数据之前，无法经由该管道模拟。 <br>〖1369〗-注册表子树的事务处理状态与请求状态不一致。 <br>〖1370〗-安全性数据库内部出现损坏。 <br>〖1371〗-无法在内置帐户上运行此操作。 <br>〖1372〗-无法在内置特殊组上运行此操作。 <br>〖1373〗-无法在内置特殊用户上运行此操作。 <br>〖1374〗-无法从组中删除用户，因为当前组为用户的主要组。 <br>〖1375〗-令牌已作为主要令牌使用。 <br>〖1376〗-指定的本地组不存在。 <br>〖1377〗-指定的帐户名不是本地组的成员。 <br>〖1378〗-指定的帐户名已是本地组的成员。 <br>〖1379〗-指定的本地组已存在。 <br>〖1380〗-登录失败: 未授予用户在此计算机上的请求登录类型。 <br>〖1381〗-已超过在单一系统中可保存机密的最大个数。 <br>〖1382〗-机密的长度超过允许的最大长度。 <br>〖1383〗-本地安全颁发机构数据库内部包含不一致性。 <br>〖1384〗-在尝试登录的过程中，用户的安全上下文积累了过多的安全标识。 <br>〖1385〗-登录失败: 未授予用户在此计算机上的请求登录类型。 <br>〖1386〗-更改用户密码时需要交叉加密密码。 <br>〖1387〗-由于成员不存在，无法将成员添加到本地组中，也无法从本地组将其删除。 <br>〖1388〗-无法将新成员加入到本地组中，因为成员的帐户类型错误。 <br>〖1389〗-已指定过多的安全标识。 <br>〖1390〗-更改此用户密码时需要交叉加密密码。 <br>〖1391〗-表明 ACL 未包含任何可承继的组件。 <br>〖1392〗-文件或目录损坏且无法读取。 <br>〖1393〗-磁盘结构损坏且无法读取。 <br>〖1394〗-无任何指定登录会话的用户会话项。 <br>〖1395〗-正在访问的服务有连接数目标授权限制。这时候已经无法再连接，原因是已经到达可接受的连接数目上限。 <br>〖1396〗-登录失败: 该目标帐户名称不正确。 <br>〖1397〗-相互身份验证失败。该服务器在域控制器的密码过期。 <br>〖1398〗-在客户机和服务器之间有一个时间差。 <br>〖1400〗-无效的窗口句柄。 <br>〖1401〗-无效的菜单句柄。 <br>〖1402〗-无效的光标句柄。 <br>〖1403〗-无效的加速器表句柄。 <br>〖1404〗-无效的挂钩句柄。 <br>〖1405〗-无效的多重窗口位置结构句柄。 <br>〖1406〗-无法创建最上层子窗口。 <br>〖1407〗-找不到窗口类别。 <br>〖1408〗-无效窗口；它属于另一线程。 <br>〖1409〗-热键已注册。 <br>〖1410〗-类别已存在。 <br>〖1411〗-类别不存在。 <br>〖1412〗-类别仍有打开的窗口。 <br>〖1413〗-无效索引。 <br>〖1414〗-无效的图标句柄。 <br>〖1415〗-使用专用 DIALOG 窗口字。 <br>〖1416〗-找不到列表框标识。 <br>〖1417〗-找不到通配字符。 <br>〖1418〗-线程没有打开的剪贴板。 <br>〖1419〗-没有注册热键。 <br>〖1420〗-窗口不是合法的对话窗口。 <br>〖1421〗-找不到控件 ID。 <br>〖1422〗-因为没有编辑控制，所以组合框的消息无效。 <br>〖1423〗-窗口不是组合框。 <br>〖1424〗-高度必须小于 256。 <br>〖1425〗-无效的设备上下文(DC)句柄。 <br>〖1426〗-无效的挂接程序类型。 <br>〖1427〗-无效的挂接程序。 <br>〖1428〗-没有模块句柄无法设置非本机的挂接。 <br>〖1429〗-此挂接程序只可整体设置。 <br>〖1430〗-Journal Hook 程序已安装。 <br>〖1431〗-挂接程序尚未安装。 <br>〖1432〗-单一选择列表框的无效消息。 <br>〖1433〗-LB_SETCOUNT 发送到非被动的列表框。 <br>〖1434〗-此列表框不支持 Tab 键宽度。 <br>〖1435〗-无法毁坏由另一个线程创建的对象。 <br>〖1436〗-子窗口没有菜单。 <br>〖1437〗-窗口没有系统菜单。 <br>〖1438〗-无效的消息对话框样式。 <br>〖1439〗-无效的系统范围内的 (SPI_*) 参数。 <br>〖1440〗-已锁定屏幕。 <br>〖1441〗-多重窗口位置结构中窗口的所有句柄必须具有相同的上层。 <br>〖1442〗-窗口不是子窗口。 <br>〖1443〗-无效的 GW_* 命令。 <br>〖1444〗-无效的线程标识。 <br>〖1445〗-无法处理非多重文档界面 (MDI) 窗口中的消息。 <br>〖1446〗-弹出式菜单已经激活。 <br>〖1447〗-窗口没有滚动条。 <br>〖1448〗-滚动条范围不可大于 MAXLONG。 <br>〖1449〗-无法以指定的方式显示或删除窗口。 <br>〖1450〗-系统资源不足，无法完成请求的服务。 <br>〖1451〗-系统资源不足，无法完成请求的服务。 <br>〖1452〗-系统资源不足，无法完成请求的服务。 <br>〖1453〗-配额不足，无法完成请求的服务。 <br>〖1454〗-配额不足，无法完成请求的服务。 <br>〖1455〗-页面文件太小，无法完成操作。 <br>〖1456〗-找不到菜单项。 <br>〖1457〗-键盘布局句柄无效。 <br>〖1458〗-不允许使用挂钩类型。 <br>〖1459〗-该操作需要交互式窗口工作站。 <br>〖1460〗-由于超时时间已过，该操作返回。 <br>〖1461〗-无效监视器句柄。 <br>〖1500〗-事件日志文件损坏。 <br>〖1501〗-无法打开事件日志文件，事件日志服务没有启动。 <br>〖1502〗-事件日志文件已满。 <br>〖1503〗-事件日志文件已在读取间更改。 <br>〖1601〗-无法访问 Windows 安装服务。请与技术支持人员联系，确认 Windows 安装服务是否注册正确。 <br>〖1602〗-用户取消了安装。 <br>〖1603〗-安装时发生严重错误 <br>〖1604〗-安装已挂起，未完成。 <br>〖1605〗-这个操作只对当前安装的产品有效。 <br>〖1606〗-功能 ID 未注册。 <br>〖1607〗-组件 ID 并未注册。 <br>〖1608〗-未知属性。 <br>〖1609〗-句柄处于不正确的状态。 <br>〖1610〗-这个产品的配置数据已损坏。请与技术支持人员联系。 <br>〖1611〗-组件限制语不存在。 <br>〖1612〗-这个产品的安装来源无法使用。请验证来源是否存在，是否可以访问。 <br>〖1613〗-Windows 安装服务无法安装这个安装程序包。您必须安装含有 Windows 安装服务新版本的 Windows Service Park。 <br>〖1614〗-没有卸载产品。 <br>〖1615〗-SQL 查询语法不正确或不被支持。 <br>〖1616〗-记录字符域不存在。 <br>〖1617〗-设备已被删除. <br>〖1618〗-正在进行另一个安装操作。请在继续这个安装操作之前完成那个操作。 <br>〖1619〗-未能打开这个安装程序包。请验证程序包是否存在，是否可以访问；或者与应用程序供应商联系，验证这是否是有效的 Windows 安装服务程序包。 <br>〖1620〗-未能打开这个安装程序包。请与应用程序供应商联系，验证这是否是有效的 Windows 安装服务程序包。 <br>〖1621〗-启动 Windows 安装服务用户界面时有错误。请与技术支持人员联系。 <br>〖1622〗-打开安装日志文件的错误。请验证指定的日志文件位置是否存在，是否可以写入。 <br>〖1623〗-安装程序包的语言不受系统支持。 <br>〖1624〗-应用变换时的错误。请验证指定的变换路径是否有效。 <br>〖1625〗-系统策略禁止这个安装。请与系统管理员联系。 <br>〖1626〗-无法执行函数。 <br>〖1627〗-执行期间，函数出了问题。 <br>〖1628〗-指定了无效的或未知的表格。 <br>〖1629〗-提供的数据类型不对。 <br>〖1630〗-这个类型的数据不受支持。 <br>〖1631〗-Windows 安装服务未能启动。请与技术支持人员联系。 <br>〖1632〗-临时文件夹已满或无法使用。请验证临时文件夹是否存在，是否可以写入。 <br>〖1633〗-这个处理器类型不支持该安装程序包。请与产品供应商联系。 <br>〖1634〗-组件没有在这台计算机上使用。 <br>〖1635〗-无法打开修补程序包。请验证修补程序包是否存在，是否可以访问；或者与应用程序供应商联系，验证这是否是 Windows 安装服务的修补程序包。 <br>〖1636〗-无法打开修补程序包。请与应用程序供应商联系，验证这是否是 Windows 安装服务的修补程序包。 <br>〖1637〗-Windows 安装服务无法处理这个插入程序包。您必须安装含有 Windows 安装服务新版本的 Windows Service Pack。 <br>〖1638〗-已安装这个产品的另一个版本。这个版本的安装无法继续。要配置或删除这个产品的现有版本，请用&#8220;控制面板&#8221;上的&#8220;添加/删除程序&#8221;。 <br>〖1639〗-无效的命令行参数。有关详细的命令行帮助，请查阅 Windows 安装服务的 SDK。 <br>〖1640〗-在终端服务远程会话期间，只有管理员有添加、删除或配置服务器软件的权限。如果您要在服务器上安装或配置软件，请与网络管理员联系。 <br>〖1641〗-要求的操作已成功结束。要使改动生效，必须重新启动系统。 <br>〖1642〗-Windows 安装服务无法安装升级修补程序，因为被升级的程序可能会丢失或是升级修补程序可能更新此程序的一个不同版本。请确认要被升级的程序在您的计算机上且您的升级修补程序是正确的。 <br>〖1700〗-串绑定无效。 <br>〖1701〗-绑定句柄类型不正确。 <br>〖1702〗-绑定句柄无效。 <br>〖1703〗-不支持 RPC 协议序列。 <br>〖1704〗-RPC 协议序列无效。 <br>〖1705〗-字符串通用唯一标识 (UUID) 无效。 <br>〖1706〗-终结点格式无效。 <br>〖1707〗-网络地址无效。 <br>〖1708〗-找不到终结点。 <br>〖1709〗-超时值无效。 <br>〖1710〗-找不到对象通用唯一标识(UUID)。 <br>〖1711〗-对象通用唯一标识 (UUID)已注册。 <br>〖1712〗-类型通用唯一标识(UUID)已注册。 <br>〖1713〗-RPC 服务器已在侦听。 <br>〖1714〗-未登记任何协议序列。 <br>〖1715〗-RPC 服务器未在侦听。 <br>〖1716〗-未知的管理器类型。 <br>〖1717〗-未知的界面。 <br>〖1718〗-没有任何链接。 <br>〖1719〗-无任何协议顺序。 <br>〖1720〗-无法创建终结点。 <br>〖1721〗-资源不足，无法完成此操作。 <br>〖1722〗-RPC 服务器不可用。 <br>〖1723〗-RPC 服务器过忙以致无法完成此操作。 <br>〖1724〗-网络选项无效。 <br>〖1725〗-在此线程中，没有使用中的远程过程调用。 <br>〖1726〗-远程过程调用失败。 <br>〖1727〗-远程过程调用失败且未运行。 <br>〖1728〗-远程过程调用(RPC)协议出错。 <br>〖1730〗-RPC 服务器不支持传送语法。 <br>〖1732〗-不支持通用唯一标识(UUID)类型。 <br>〖1733〗-标记无效。 <br>〖1734〗-数组边界无效。 <br>〖1735〗-链接不包含项目名称。 <br>〖1736〗-名称语法无效。 <br>〖1737〗-不支持名称语法。 <br>〖1739〗-没有可用来创建通用唯一标识 (UUID)的网络地址。 <br>〖1740〗-终结点是一份备份。 <br>〖1741〗-未知的验证类型。 <br>〖1742〗-调用的最大个数太小。 <br>〖1743〗-字符串太长。 <br>〖1744〗-找不到 RPC 协议顺序。 <br>〖1745〗-过程号超出范围。 <br>〖1746〗-绑定不包含任何验证信息。 <br>〖1747〗-未知的验证服务。 <br>〖1748〗-未知的验证级别。 <br>〖1749〗-安全上下文无效。 <br>〖1750〗-未知的授权服务。 <br>〖1751〗-项目无效。 <br>〖1752〗-服务器终结点无法运行操作。 <br>〖1753〗-终结点映射表中无更多的可用终结点。 <br>〖1754〗-未导出任何界面。 <br>〖1755〗-项目名称不完整。 <br>〖1756〗-版本选项无效。 <br>〖1757〗-没有其他成员。 <br>〖1758〗-没有内容未导出。 <br>〖1759〗-接口没有找到。 <br>〖1760〗-项目已存在。 <br>〖1761〗-找不到项目。 <br>〖1762〗-无可用的名称服务。 <br>〖1763〗-网络地址族无效。 <br>〖1764〗-不支持请求的操作。 <br>〖1765〗-无可用的安全上下文以允许模拟。 <br>〖1766〗-远程过程调用(RPC)中发生内部错误。 <br>〖1767〗-RPC 服务器试图以零除整数。 <br>〖1768〗-RPC 服务器中发生地址错误。 <br>〖1769〗-RPC 服务器上的浮点操作导至以零做除数。 <br>〖1770〗-RPC 服务器上发生浮点下溢。 <br>〖1771〗-RPC 服务器上发生浮点上溢。 <br>〖1772〗-自动句柄绑定的可用 RPC 服务器列表已用完。 <br>〖1773〗-无法打开字符翻译表文件。 <br>〖1774〗-包含字符翻译表的文件少于512 字节。 <br>〖1775〗-在远程过程调用时，将空的上下文句柄从客户传递到主机。 <br>〖1777〗-在远程过程调用时，上下文句柄已更改。 <br>〖1778〗-传递到远程过程调用的绑定句柄不相符。 <br>〖1779〗-承接体无法获得远程过程调用句柄。 <br>〖1780〗-传递空引用指针到承接体。 <br>〖1781〗-列举值超出范围。 <br>〖1782〗-字节计数太小。 <br>〖1783〗-承接体接收到坏数据。 <br>〖1784〗-提供给请求操作的用户缓冲区无效。 <br>〖1785〗-磁盘媒体无法识别。可能未被格式化。 <br>〖1786〗-工作站没有信任机密。 <br>〖1787〗-服务器上的安全数据库没有此工作站信任关系的计算机帐户。 <br>〖1788〗-主域和受信域间的信任关系失败。 <br>〖1789〗-此工作站和主域间的信任关系失败。 <br>〖1790〗-网络登录失败。 <br>〖1791〗-此线程的远程过程调用已在进行中。 <br>〖1792〗-试图登录，但是网络登录服务没有启动。 <br>〖1793〗-用户帐户到期。 <br>〖1794〗-转发程序已被占用且无法卸载。 <br>〖1795〗-指定的打印机驱动程序已安装。 <br>〖1796〗-指定的端口未知。 <br>〖1797〗-未知的打印机驱动程序。 <br>〖1798〗-未知的打印机处理器。 <br>〖1799〗-指定的分隔页文件无效。 <br>〖1800〗-指定的优先级无效。 <br>〖1801〗-打印机名无效。 <br>〖1802〗-打印机已存在。 <br>〖1803〗-打印机命令无效。 <br>〖1804〗-指定的数据类型无效。 <br>〖1805〗-指定的环境无效。 <br>〖1806〗-没有更多的绑定。 <br>〖1807〗-所用帐户为域间信任帐户。请使用您的全局用户帐户或本地用户帐户来访问这台服务器。 <br>〖1808〗-所用帐户是一个计算机帐户。使用您的全局用户帐户或本地用户帐户来访问此服务器。 <br>〖1809〗-已使用的帐户为服务器信任帐户。使用您的全局用户帐户或本地用户帐户来访问此服务器。 <br>〖1810〗-指定域的名称或安全标识(SID)与该域的信任信息不一致。 <br>〖1811〗-服务器在使用中且无法卸载。 <br>〖1812〗-指定的映像文件不包含资源区域。 <br>〖1813〗-找不到映像文件中指定的资源类型。 <br>〖1814〗-找不到映像文件中指定的资源名。 <br>〖1815〗-找不到映像文件中指定的资源语言标识。 <br>〖1816〗-配额不足，无法处理此命令。 <br>〖1817〗-未登记任何界面。 <br>〖1818〗-远程过程调用被取消。 <br>〖1819〗-绑定句柄不包含所有需要的信息。 <br>〖1820〗-在远程过程调用过程中通讯失败。 <br>〖1821〗-不支持请求的验证级别。 <br>〖1822〗-未登记任何主名称。 <br>〖1823〗-指定的错误不是有效的 Windows RPC 错误码。 <br>〖1824〗-已配置一个只在这部计算机上有效的 UUID。 <br>〖1825〗-发生一个安全包特有的错误。 <br>〖1826〗-线程未取消。 <br>〖1827〗-无效的编码/解码句柄操作。 <br>〖1828〗-序列化包装的版本不兼容。 <br>〖1829〗-RPC 承接体的版本不兼容。 <br>〖1830〗-RPC 管道对象无效或已损坏。 <br>〖1831〗-试图在 RPC 管道物件上进行无效操作。 <br>〖1832〗-不被支持的 RPC 管道版本。 <br>〖1898〗-找不到该组成员。 <br>〖1899〗-无法创建终结点映射表数据库项。 <br>〖1900〗-对象通用唯一标识 (UUID) 为 nil UUID。 <br>〖1901〗-指定的时间无效。 <br>〖1902〗-指定的格式名称无效。 <br>〖1903〗-指定的格式大小无效。 <br>〖1904〗-指定的打印机句柄正等候在 <br>〖1905〗-已删除指定的打印机。 <br>〖1906〗-打印机的状态无效。 <br>〖1907〗-在第一次登录之前，必须更改用户密码。 <br>〖1908〗-找不到此域的域控制器。 <br>〖1909〗-引用的帐户当前已锁定，且可能无法登录。 <br>〖1910〗-没有发现指定的此对象导出者 <br>〖1911〗-没有发现指定的对象。 <br>〖1912〗-没有发现指定的对象解析器。 <br>〖1913〗-一些待发数据仍停留在请求缓冲区内。 <br>〖1914〗-无效的异步远程过程调用句柄。 <br>〖1915〗-这个操作的异步 RPC 调用句柄不正确。 <br>〖1916〗-RPC 管道对象已经关闭。 <br>〖1917〗-在 RPC 调用完成之前全部的管道都已处理完成。 <br>〖1918〗-没有其他可用的数据来自 RPC 管道。 <br>〖1919〗-这个机器没有可用的站点名。 <br>〖1920〗-系统无法访问此文件。 <br>〖1921〗-系统无法辨识文件名。 <br>〖1922〗-项目不是所要的类型。 <br>〖1923〗-无法将所有对象的 UUID 导出到指定的项。 <br>〖1924〗-无法将界面导出到指定的项。 <br>〖1925〗-无法添加指定的配置文件项。 <br>〖1926〗-无法添加指定的配置文件元素。 <br>〖1927〗-无法删除指定的配置文件元素。 <br>〖1928〗-无法添加组元素。 <br>〖1929〗-无法删除组元素。<img src ="http://www.cppblog.com/momoxiao/aggbug/108424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-25 14:02 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/25/108424.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动安装包制作 nsis</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/24/108378.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Wed, 24 Feb 2010 14:58:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/24/108378.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/108378.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/24/108378.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/108378.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/108378.html</trackback:ping><description><![CDATA[<p dir="ltr" style="margin-right: 0px;">引用不知道哪位大牛的原话：<br><br>对于即插即用简单地说要对付2种情况 <br>1。在你的设备未安装前，安装驱动程序这叫预先安装。 <br>最简单的方法就是使用SetupCopyOEMInf函数。 <br>具体做法是： <br>将SetupCopyOEMInf封装在一个动态库里。 <br>用installshield将所有文件copy到一个临时目录。 <br>调用动态库使用SetupCopyOEMInf函数copy临时目录下的inf文件（路径）。 <br>installshield让计算机重启。 <br>插上设备，自动识别。&nbsp;<br>&nbsp;2.你的设备已安装，弹出安装向导。 <br>很简单，让用户搜索你的安装盘，即可完成安装。<br>&nbsp;<br>懒得写dll了(其实是不会写- -)，devcon dp_add调用SetupCopyOEMInf做了预安装<br></p>
<hr>
<br><br>wdk文档中关于预安装的一段话<br>我刚开始以为预安装就是直接把驱动安上，白痴似的把驱动直接安上了，然后我机子上面之前的驱动没卸干净，添上设备后直接能用，偶就把安装程序当成一个版本交了，囧。。。
<p>&nbsp;</p>
<p class="MsoNormal" style="margin: 6pt 0cm 6pt -17.65pt; text-align: left;" align="left"><a name="custom-install_3992c8de-10d6-4f6e-8309-7"></a><strong><span style="font-size: 12.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">Preinstalling Driver Packages<o:p></o:p></span></strong></p>
<p class="MsoNormal" style="margin: 7.2pt 0cm; text-align: left;" align="left"><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">To preinstall driver files, your device installation application should follow these steps:<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 7.2pt 43.2pt; text-indent: -18pt; text-align: left;" align="left"><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US"><span>1.<span style="font: 7pt 'Times New Roman';"> </span></span></span><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">On the target system, create a directory for the driver files. If your device installation application installs an application, the driver files should be stored in a subdirectory of the application directory. <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 7.2pt 43.2pt; text-indent: -18pt; text-align: left;" align="left"><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US"><span>2.<span style="font: 7pt 'Times New Roman';"> </span></span></span><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">Copy all files in the </span><span lang="EN-US"><a href="ms-help://MS.WDK.v10.7600.090618.01/DevInst_d/hh/DevInst_d/drv-package_ff7c0a1d-abba-4775-b236-112d46c85169.xml.htm"><span style="font-size: 8.5pt; color: #0066ff; font-family: 宋体;"><u>driver package</u></span></a></span><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US"> from the distribution media to the directory created in step (1). The driver package includes the driver or drivers, the INF file, the catalog file, and other installation files. <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 7.2pt 43.2pt; text-indent: -18pt; text-align: left;" align="left"><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US"><span>3.<span style="font: 7pt 'Times New Roman';"> </span></span></span><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">Call <span><v:shapetype id="_x0000_t75" filled="f" coordsize="21600,21600" stroked="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="图片_x0020_1" style="visibility: visible; width: 8.25pt; height: 8.25pt;" type="#_x0000_t75" o:spid="_x0000_i1025" alt="ms-help://MS.WDK.v10.7600.090618.01/DevInst_d/hh/DevInst_d/internet_link_sm.gif"><v:imagedata o:title="internet_link_sm" src="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image001.gif"></v:imagedata></v:shape></span>&nbsp;</span><span lang="EN-US"><a href="http://go.microsoft.com/fwlink/?linkid=98735" target="_blank"><strong><span style="font-size: 8.5pt; color: #0066ff; font-family: 宋体;"><u>SetupCopyOEMInf</u></span></strong></a></span><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US"> specifying the INF file in the directory created in step (1). Specify SPOST_PATH for the <em>OEMSourceMediaType</em> parameter and specify NULL for the <em>OEMSourceMediaLocation</em> parameter. <strong>SetupCopyOEMInf</strong> <span style="background: none repeat scroll 0% 0% yellow;">copies the INF file for the driver package into the <em>%windir%\Inf</em> directory</span> on the target system and directs Windows to store the source location of the INF file in its list of preprocessed INF files. <strong>SetupCopyOEMInf</strong> also processes the catalog file, so <span style="background: none repeat scroll 0% 0% yellow;">the PnP manager will install the driver the next time it recognizes a device listed in the INF file</span>. <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 7.2pt 0cm; text-align: left;" align="left"><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">When the user plugs in the device, the PnP manager recognizes the device, finds the INF file copied by <strong>SetupCopyOEMInf</strong>, and installs the drivers copied in step (2). (For more information about copying INF files, see </span><span lang="EN-US"><a href="ms-help://MS.WDK.v10.7600.090618.01/DevInst_d/hh/DevInst_d/create-inf_7829a513-3c62-442b-8c3c-66cdb4469fda.xml.htm"><span style="font-size: 8.5pt; color: #0066ff; font-family: 宋体;"><u>Copying INFs</u></span></a></span><span style="font-size: 8.5pt; color: black; font-family: 'verdana','sans-serif';" lang="EN-US">.)<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="EN-US"><o:p><font face="Calibri">&nbsp;
<hr>
</font></o:p></span>
</p>
<p>&nbsp;</p>
<p align="left">安装时直接把inf文件拷windows\inf下，卸载时删除，防止被命名成oem*.inf，在某种情况下发生重复预注册，同时也便于卸载时删除inf文件<br><o:p><br>
</o:p></p>
<hr>
<p>&nbsp;</p>
<p><o:p>&nbsp;未完待续。。。</o:p></p><img src ="http://www.cppblog.com/momoxiao/aggbug/108378.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-24 22:58 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/24/108378.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>批量删除注册表</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/24/108376.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Wed, 24 Feb 2010 14:41:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/24/108376.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/108376.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/24/108376.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/108376.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/108376.html</trackback:ping><description><![CDATA[写个bat文件<br>reg delete 注册表目录<br>权限不够的表象，reg<font size="+0">i</font>n<font size="+0">i</font> ***.<font size="+0">i</font>n<font size="+0">i</font>后再删<br><font size="+0">i</font>n<font size="+0">i</font> 文件的格式：注册表目录 [权限]<br><br>例子一个：<br>xxxx是和项目有关的东西，隐去了，这个bat文件reg delete后面都是目录的名字- -<br>注意有权限的注册表删除的时候,如果a目录下有b,b目录下有c,c下面没有目录了，删除的顺序是c,b,a，只给a目录设权限删a目录删不掉，因为b,c没有继承a的权限<br>哦，在regini的配置文件里把3个都设权限，然后bat里只reg delete a不知道行不行，忘试了<br>limit.ini<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #000000;">HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\xxxx[</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">7</span><span style="color: #000000;">]<br><br>HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ictBus\xxxx[</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">7</span><span style="color: #000000;">]<br><br>HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\xxxx\xxxx\</span><span style="color: #000000;">1</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">2d12bed1</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">0</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">0000</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">7</span><span style="color: #000000;">]</span></div>
<br><br>del.bat<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98.75%; height: 533px; background-color: #eeeeee;"><span style="color: #000000;">reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Control\Class\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx}\0001</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Control\Cr<font size="+0">i</font>t<font size="+0">ic</font>alDev<font size="+0">ic</font>eDatabase\xxxxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Control\Cr<font size="+0">i</font>t<font size="+0">ic</font>alDev<font size="+0">ic</font>eDatabase\xxxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Enum\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Serv<font size="+0">ic</font>es\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Serv<font size="+0">ic</font>es\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet002\Serv<font size="+0">ic</font>es\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet002\Enum\Root\LEGACY_xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet002\ControlSet002\Enum\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\CurrentControlSet\Control\Cr<font size="+0">i</font>t<font size="+0">ic</font>alDev<font size="+0">ic</font>eDatabase\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg<font size="+0">i</font>n<font size="+0">i</font>&nbsp;l<font size="+0">i</font>m<font size="+0">i</font>t.<font size="+0">i</font>n<font size="+0">i</font><br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Enum\xxxx\xxxx\1&amp;2d12bed1&amp;0&amp;0000</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Enum\xxxx\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br>reg&nbsp;delete&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">HKEY_LOCAL_MACH<font size="+0">I</font>NE\SYSTEM\ControlSet001\Enum\xxxx</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">f<br><br><br><br><br><br><br><br><br></span></div>
<br><br>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">regini 权限代码表 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;1&nbsp; - Administrators 完全访问<br>&nbsp;2&nbsp; - Administrators 读取访问<br>&nbsp;3&nbsp; - Administrators 读取、写入访问<br>&nbsp;4&nbsp; - Administrators 读取、写入、删除访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;5&nbsp; - Creator 完全访问<br>&nbsp;6&nbsp; - Creator 读取、写入访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;7&nbsp; - everyone 完全访问<br>&nbsp;8&nbsp; - everyone 读取访问<br>&nbsp;9&nbsp; - everyone 读取、写入访问<br>&nbsp;10 - everyone 读取、写入、删除访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;11 - Power Users 完全访问<br>&nbsp;12 - Power Users 读取、写入访问<br>&nbsp;13 - Power Users 读取、写入、删除访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;14 - System Operators 完全访问<br>&nbsp;15 - System Operators 读取、写入访问<br>&nbsp;16 - System Operators 读取、写入、删除访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;17 - System 完全访问<br>&nbsp;18 - System 读取、写入访问<br>&nbsp;19 - System 读取访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;20 - Administrators 读取、写入、执行访问 </font></p>
<p style="font-family: Courier;"><font size="2" color="#808080" face="Courier New">&nbsp;21 - Interactive User 完全访问<br>&nbsp;22 - Interactive User 读取、写入访问<br>&nbsp;23 - Interactive User 读取、写入、删除访问 </font></p><img src ="http://www.cppblog.com/momoxiao/aggbug/108376.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-24 22:41 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/24/108376.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows驱动编程基础教程－谭文－代码整理</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/24/108375.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Wed, 24 Feb 2010 14:20:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/24/108375.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/108375.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/24/108375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/108375.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/108375.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Windows驱动编程基础教程－谭文－代码整理基本上是教程上原代码照抄，只给代码做了个排列组合，改了一些作者的小笔误代码全部测试通过，测试环境：WinDDK 7600.16385.0 chk x86 WXP教程上有很详细非常详细的讲解，偶就偷懒不写注释了代码中有些应该考虑应该实现的东西偶不会，就省了。。。不会完善，能跑就行。。。1 字符串使用2 内存的分配与释放3 LIST_ENTRY4 LARG...&nbsp;&nbsp;<a href='http://www.cppblog.com/momoxiao/archive/2010/02/24/108375.html'>阅读全文</a><img src ="http://www.cppblog.com/momoxiao/aggbug/108375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-24 22:20 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/24/108375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RING0和RING3穿透还原软件zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107341.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:22:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107341.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107341.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107341.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107341.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107341.html</trackback:ping><description><![CDATA[写了两天的程序，总算把RING3下的搞定了。这个太强悍了，可以穿透所有的主动防御和还原软件和影子系统~~危害太大，代码我就不发了~~关于RING0驱动过还原的可以看机器狗的代码~
<p><font size="3">　　随着机器狗病毒和MJ的Tophet.a的放出，无论是RING0还是RING3下穿透还原软件的技术突然浮现在了大众的眼前。让你的毒毒和小马能穿透还原软件/卡，的确很吸引人~~<br>　　最近学习SCSI总线命令，结合以前的知识做了一下穿透还原软件，学习是个曲线前进过程，有可能文中有些观点不对，主要来自《SCSI程序员指南》和《scsi总线及IDE接口（协议、应用和编程）》~~</font></p>
<p><font size="3">IRP是从文件系统-&gt;卷驱动 -&gt; 磁盘驱动-&gt; 类驱动-&gt; 端口驱动-&gt; 微端口驱动<br>ntfs/fat32.sys-&gt;partmgr.sys-&gt;ftdisk.sys-&gt;disk.sys-&gt;classpnp.sys-&gt;acpi.sys-&gt;atapi.sys<br>　　其中不少是value-added和filter驱动，主要的是文件系统驱动ntfs/fat32.sys，storage驱动disk.sys和总线驱动atapi.sys，我们知道，文件系统驱动做的工作就是把下层读扇区得到的RAW数据转换成文件，向上提供，磁盘驱动这层就是把上层请求的读扇区的IRP换成带SCSI命令的IRP</font><font size="3">发给下层的miniport ATAPI.sys，ATAPI.sys调用hal中的write_port_char最后来直接端口I/O了。还原程序是在哪一层呢？是在disk.sys之上插了一个filter，如果直接绕过上层的驱动直接发带SRB的IRP给Disk.sys或是ATAPI.sys,那么就实现了穿透。另外，当然还有别的方法，譬如</font><font size="3">端口I/O，但是通用性不好，与硬盘具体的接口有关(IDE,SCSI等)<br>kd&gt;bu atapi!IdePortStartIo</font></p>
<img src="http://www.cppblog.com/images/cppblog_com/momoxiao/cfa1cd6283b3ae480d33fa0e.jpg" border="0"><br>上图可看到，在disk这层的irp处理交给了classpnp了，在disk这层之上有个DeepFrz的驱动，这是我测试用的冰点还原的驱动，可以的确冰点还原的驱动是位于disk之上的，从理论上说我们发SRB给disk是可以绕过还原的。到了atapi这层就是走atapi!IdePortStartIo-&gt;nt!IoStartPacket-&gt;IdePortStartIo,之后就分有无DMA能力区别对待了。<br>　　首先SCSI总线上设备数据传输的过程:<br>申请—仲裁（建立连接）—消息—命令—数据（如果命令产生数据传输）—消息（通知结束，发送状态码）<br>SCSI有以下几个阶段:<br>1总线空闲阶段<br>2总裁阶段<br>3选择阶段<br>4重新选择阶段<br>5消息输出阶段<br>6命令阶段（接受CDB）<br>CDB分为0，1，2，5号组命令，命令组号告诉目标器在CDB中有多少字节，然后会产生以下三种阶段情况(本段参考《SCSI程序员指南》，比较老<font size="3">了，根据SCSI SPC-3上有16字节的等)<br>0号组CDB是6字节长<br>1，2号组CDB是10字节长<br>5号组CDB是12字节长<br>CDB的第一个字节是描述该命令的操作码，高三位表示命令所属的命令组0-7，低五位表示命令码<br>CDB的第二个字节高三位表示一个LUN（逻辑单元号）<br>　　其中LUN是什么呢？LUN的全称是Logical Unit Number，也就是逻辑单元号。我们知道SCSI总线上可挂接的设备数量是有限的，一般为6个或者15个，我们可以用Target ID(也有称为SCSI ID的)来描述这些设备，而实际上我们需要用来描述的对象，是远远超过该数字的，于是我们引进了LUN的概念，也就是说LUN ID的作用就是扩充了Target ID。每个Target下都可以有多个LUN Device，我们通常简称LUN Device为LUN，这样就可以说每个设备的描述就有原来的Target x变成Target x LUN y了，那么显而易见的，我们描述设备的能力增强了。<br>　　从第三字节开始是命令参数字段，对直接存取设备来说是逻辑块地址，对传输数据的命令是传输长度<br>　　最后一个字段是Control字段，如Link标志指出该CDB是否是一系列连接命令的一部分，Flag标志决定一条连接的命令成功执行后目标器返回的状态码(6-7厂商自定，2-5保留，1标志位，0连接位）<br>　　强制命令（适用于所有设备的命令,采用大端点数）<br>00H Test unitReady<br>　　简单的报告设备是否已经为执行命令做好准备，6字节组（高三位为0）<br>03H Request Sense（读取）<br>12H Inquiry<br>　　查询设备的制造商，模型信息等<br>1DH Send Diagnostic</font>
<p><font size="3">　设备类型特定命令<br>mode sense（获取目标机操作参数信息）和mode select（改变参数）有6字节和10字节<br>Read和Write命令有6字节和10字节版本，分属与0号组和2号组<br>数据阶段<br>状态阶段<br>消息输入阶段<br>　　SCSI miniport驱动器实现了对SCSI接口适配器的直接控制。miniport驱动器对SCSI适配器进行初始化，并向硬件传输I/O请求，处理中断的产生，执行适配器水平的错误修复和记录。miniport驱动器是一种小型的仿制的SCSI I/O模型，它隐藏了SCSI适配器硬件水平上的细节内容。它提供了带有连续，低层次的借口的高水平的SCSI模型，而根本不用考虑实际的硬件接口。只要实现了规定的SCSI miniport 接口，SCSI miniport驱动器就不必对传统的SCSI适配器进行控制，这就允许外设制造商在他们的硬件上使用不同的总线接口。ATAPI设备拥有一套几乎与SCSI完全一致的命令，但是它们进行的数据传输却是基于IDE总线的。windows中的ATAPI的</font><font size="3">miniport驱动接受了低层次的SCSI命令，并把它们通过IDE总线发送出去<br>　　SCSIPORT驱动器对于系统中的所有SCSI请求提供了唯一的入口点，对系统中各种各样的miniport驱动器进行初始化，把系统特有的SCSI I/O请求转化成标准的SRB，并把这些请求发送给适当的miniport驱动器。由于硬件细节被隐藏在了miniport驱动器中，所以高层次的驱动器可以调用SCSIPORT驱动器来执行所有的SCSI I/O操作，而不必在乎所使用的硬件接口，在windows NT中，有很多种标准的SCSI类驱动器，包括用来处理磁盘驱动器(disk.sys)和CD-ROM驱动器的类驱动器。文件系统的驱动器可以调用磁盘类驱动器来执行高层次，面向块的I/O请求。磁盘类驱动会把文件系统的请求转化成一系列的SCSI I/O请求，然后它们会被传送到SCSIPORT驱动。<br>　　sense data(检测数据) ：当一个SCSI设备（通常是一个LUN）发现它自己处于异常状态时，它就拒绝执行下面的命令，并返回一个check condition状态。产生至少18个</font><font size="3">字节长的数据，包括经过编码的关于错误的信息，称为检测数据。<br>IOCTL_SCSI_PASS_THROUGH<br>IOCTL_SCSI_PASS_THROUGH_DIRECT<br>　　NTFS使用逻辑簇号（Logical Cluster Number，LCN）和虚拟簇号（Virtual Cluster Number，VCN）来对簇进行定位。LCN是对整个卷中所有的簇从头到尾所进行的简单编号。用卷因子乘以LCN，NTFS就能够得到卷上的物理字节偏移量，从而得到物理磁盘地址。VCN则是对属于特定文件的簇从头到尾进行编号，以便于引用文件中的数据。VCN可以映射成LCN，而不必要求在物理上连续。<br>　　总之，不用担心下层的具体硬件接口是什么，是IDE还是SCSI，都可以用SCSI命令发给ATAPI，实现文件的读写。其实正常的文件读写也是这样</font><font size="3">的流程，只不过我们自己绕过上层，自己构造SRB而已~ </font></p>
<p><font size="3"><br>首先看驱动发SRB<br>参见</font><a href="http://www.osronline.com/DDKx/storage/k306_0hte.htm" target="_blank"><font size="3" color="#0000ff"><u>http://www.osronline.com/DDKx/storage/k306_0hte.htm</u></font></a><br><font size="3">typedef struct _SCSI_REQUEST_BLOCK {<br>&nbsp;&nbsp;&nbsp; USHORT Length;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 该SRB的长度<br>&nbsp;&nbsp;&nbsp; UCHAR Function;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 功能码，如果想发SCSI命令，设置为SRB_FUNCTION_EXECUTE_SCSI<br>&nbsp;&nbsp;&nbsp; UCHAR SrbStatus;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SRB发送后返回的状态，一般SRB发送后不会立即执行，会放入一个队列中，所以通常返回</font></p>
<p><font size="3">SRB_STATUS_PENDING<br>&nbsp;&nbsp;&nbsp; UCHAR ScsiStatus;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 是否成功发送，与上面一样均为返回值<br>&nbsp;&nbsp;&nbsp; UCHAR PathId;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 指明是总线ID,(PathId，TargetId，Lun)来确定一个设备<br>&nbsp;&nbsp;&nbsp; UCHAR TargetId;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <br>&nbsp;&nbsp;&nbsp; UCHAR Lun;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <br>&nbsp;&nbsp;&nbsp; UCHAR QueueTag;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 队列TAG<br>&nbsp;&nbsp;&nbsp; UCHAR QueueAction;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 与上述结构有关<br>&nbsp;&nbsp;&nbsp; UCHAR CdbLength;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SCSI命令块长度<br>&nbsp;&nbsp;&nbsp; UCHAR SenseInfoBufferLength;&nbsp;&nbsp;&nbsp; // 存储返回经过编码的关于错误的信息的缓冲区的长度<br>&nbsp;&nbsp;&nbsp; ULONG SrbFlags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Srb的相关参数，SRB_FLAGS_DATA_IN为读出，SRB_FLAGS_DATA_OUT为写入设备<br>&nbsp;&nbsp;&nbsp; ULONG DataTransferLength;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 指出传输数据的大小<br>&nbsp;&nbsp;&nbsp; ULONG TimeOutValue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 设定超时<br>&nbsp;&nbsp;&nbsp; PVOID DataBuffer;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 数据缓冲区<br>&nbsp;&nbsp;&nbsp; PVOID SenseInfoBuffer;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 检测缓冲区<br>&nbsp;&nbsp;&nbsp; struct _SCSI_REQUEST_BLOCK *NextSrb; // 下一个SRB，一般的命令只要一个SRB <br>&nbsp;&nbsp;&nbsp; PVOID OriginalRequest;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 指向原始IRP<br>&nbsp;&nbsp;&nbsp; PVOID SrbExtension;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <br>&nbsp;&nbsp;&nbsp; union {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG InternalStatus;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG QueueSortKey;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // <br>&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp; UCHAR Cdb[16];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SCSI总线命令了，这里不一定是16字节，正如上面所说，具体几个字节，得看第一个字节。<br>} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;<br>　　SRB是与操作系统相关的，即是操作系统定义的结构，不在SCSI规范里的，相当于对CDB的一层包裹。而真正执行命令的是CDB</font></p>
<img src="http://www.cppblog.com/images/cppblog_com/momoxiao/245314fa2683a80a4e4aea0c.jpg" border="0"><br>取自SCSI Primary Commands - 3<br>　　因为一般硬盘不会太大，10字节的DiskPos是32位的，可以操作4g*512字节的空间，一般已经足够了，如果要大点的话，可以用12字节，16字节的CDB（可去参考SCSI Primary Commands - 3）具体结合机器狗的AtapiReadWriteDisk函数进行学习~<br>ULONG AtapiReadWriteDisk(PDEVICE_OBJECT dev_object,ULONG MajorFunction, PVOID buffer,ULONG DiskPos, int BlockCount)<br>{<br>//dev_object为通过ObReferenceObjectByName得到的disk.sys设备对象，另外说句题外话，根
<p><font size="3">//据MJ的说法，disk.sys对于上层的SCSI_PASS_THROUGH是直接转发给总线设备，那么构造</font></p>
<p><font size="3">//相应的IRP直接发给总线设备也可以~这样貌似更底层<br>//MajorFunction为自定义的一个参数，根据传输进来IRP功能IRP_MJ_READ和IRP_MJ_WRITE</font></p>
<p><font size="3">//来转换。可以查SCSI Primary Commands - 3的B章的operation codes知道10字节的写为2Ah，</font></p>
<p><font size="3">//读为28h，机器狗代码中是将2*((UCHAR)MajorFunction+ 17)付给了srb-&gt;Cdb[0]，我们知道ntd</font></p>
<p><font size="3">//dk.h中定义IRP_MJ_READ为0x3，IRP_MJ_WRITE为0x4，其实这只是个简单的换算而已<br>//buffer为输入输出的缓冲区<br>//DiskPos为32位指定的磁盘起始逻辑扇区号<br>//BlockCount为要读（写）的扇区数<br>......<br>srb-&gt;Length=sizeof(SCSI_REQUEST_BLOCK);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Function=0;&nbsp;&nbsp;&nbsp;&nbsp; //0即是SRB_FUNCTION_EXECUTE_SCSI<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;DataBuffer=buffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;DataTransferLength=BlockCount&lt;&lt;9;//因为每扇区是512字节<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;QueueAction=SRB_FLAGS_DISABLE_AUTOSENSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SrbStatus=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;ScsiStatus=0;//这两个都是输出，随便填<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;NextSrb=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SenseInfoBuffer=sense;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SenseInfoBufferLength=sizeof(SENSE_DATA);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(MajorFunction==IRP_MJ_READ)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SrbFlags=SRB_FLAGS_DATA_IN;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SrbFlags=SRB_FLAGS_DATA_OUT;</font></p>
<p><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(MajorFunction==IRP_MJ_READ)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SrbFlags|=SRB_FLAGS_ADAPTER_CACHE_ENABLE;</font></p>
<p><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;SrbFlags|=SRB_FLAGS_DISABLE_AUTOSENSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;TimeOutValue=(srb-&gt;DataTransferLength&gt;&gt;10)+1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;QueueSortKey=DiskPos;//指定从目标设备的开始位置<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;CdbLength=10;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[0]=2*((UCHAR)MajorFunction+ 17);//参见上图10字节CDB的格式<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[1]=srb-&gt;Cdb[1] &amp; 0x1F | 0x80;//高三位是保留位，与0x1f清0高三位，高位置1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[2]=(unsigned char)(DiskPos&gt;&gt;0x18)&amp;0xFF;&nbsp;&nbsp;&nbsp;&nbsp; //大端点数，右移24位，取高8位放入Cdb<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[3]=(unsigned char)(DiskPos&gt;&gt;0x10)&amp;0xFF;&nbsp;&nbsp;&nbsp;&nbsp; //<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[4]=(unsigned char)(DiskPos&gt;&gt;0x08)&amp;0xFF;&nbsp;&nbsp;&nbsp;&nbsp; //<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[5]=(UCHAR)DiskPos;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //填写sector位置<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[7]=(UCHAR)BlockCount&gt;&gt;0x08;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; srb-&gt;Cdb[8]=(UCHAR)BlockCount;<br>......<br>}<br>　　当然SRB也是属于IRP中一部分，自己发IRP给总线设备，当然还得自己填充IRP包，这个就不具体讨论了<br>　　总的思路是：先发IoControlCode=FSCTL_GET_RETRIEVAL_POINTERS的IRP给文件系统驱动，得到某个文件的起始逻辑扇区号和大小，然后得到disk.sys的dev，再发构造好的SRB的IRP给disk.sys就ok了，这样就绕过了还原软件</font></p>
<p><font size="3"><br>RING3发SCSI_PASS_THROUGH：</font><font size="3"><br>遍历符号链接找到总线设备</font><font size="3">对应的符号链接，发送SCSI_PASS_THROUGH_DIRECT给总线设备实现文件读写，从而绕过主动防御，其中思路MJ0011说了，不过他给的代码基本没用，好几个暗桩~</font></p><img src ="http://www.cppblog.com/momoxiao/aggbug/107341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:22 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>终极磁盘隐藏及防护zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107340.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:19:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107340.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107340.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107340.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107340.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107340.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 终极磁盘隐藏及防护
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --SCSI miniport driver之利用</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by CuteK</p>
<p>如何利用SCSI miniport driver呢, 先了解该驱动在系统中的位置,想想大家都可以做些什么吧,</p>
<p>虚拟光驱? 还原卡? bootkit ?</p>
<p>&nbsp;</p>
<p>一, 看看windows启动链条</p>
<p>MBR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16位实模式</p>
<p>boot sector&nbsp;&nbsp;&nbsp;&nbsp; 16位实模式 读入根目录 加载ntldr</p>
<p>Ntldr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<ul style="margin-top: 0in; margin-bottom: 0in; margin-left: 0.75in; direction: ltr; unicode-bidi: embed;" type="circle">
    <li style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle;"><span style="font-size: 10pt;">将系统从</span><span style="font-size: 10pt;">16</span><span style="font-size: 10pt;">位模式切换到</span><span style="font-size: 10pt;">32</span><span style="font-size: 10pt;">位模式</span>
    </li>
    <li style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle;"><span style="font-size: 10pt;">开启</span><span style="font-size: 10pt;">(</span><span style="font-size: 10pt;">内存</span><span style="font-size: 10pt;">)</span><span style="font-size: 10pt;">分页管理</span>
    </li>
    <li style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle;"><span style="font-size: 10pt;">如果启动卷为</span><span style="font-size: 10pt;">SCSI</span><span style="font-size: 10pt;">磁盘，从系统卷上读取</span><span style="font-size: 10pt;">Ntbootdd.sys</span><span style="font-size: 10pt;">对</span><span style="font-size: 10pt;">SCSI</span><span style="font-size: 10pt;">磁盘进行</span><span style="font-size: 10pt;">I/O</span><span style="font-size: 10pt;">操作、检测</span> 不使用bios的scsi和ata使用<font color="#ff0000">Ntbootdd.sys</font> 驱动读取磁盘数据, 该驱动是SCSI miniport driver 由厂商自行开发, 开发后改为这个名字即可 ,
    </li>
    <li style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle;"><span style="font-size: 10pt;">查找启动卷中是否包含有效的</span><span style="font-size: 10pt;">Hiberfil.sys</span><span style="font-size: 10pt;">文件，如果有效，跳过如下步骤，直接读取</span><span style="font-size: 10pt;">Hiberfil.sys</span><span style="font-size: 10pt;">中的信息到内存中，是系统恢复到休眠前的状态</span> </li>
</ul>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 读取boot.ini&nbsp;&nbsp; 三种方式multi ,<font color="#ff0000">scsi, signature</font>启动, 后两种需要scsi miniport driver 帮助读取磁盘</p>
<p>Ntdetct.com&nbsp;&nbsp;&nbsp; 16位实模式</p>
<p>Ntoskrnl.exe/ntkrnlpa.exe&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>Hal.dll</p>
<p>smss</p>
<p>winlogon</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>二, 驱动所处位置</p>
<p>&nbsp;</p>
<p>SCSI miniport driver 开发比较容易因为可以调用微软提供的scsiport.sys提供的通用功能.针对具体的硬件做srb的处理</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>驱动栈层次</p>
<p>-----------------------</p>
<p>文件系统过滤驱动</p>
<p>-----------------------</p>
<p>文件驱动ntfs.sys</p>
<p>-----------------------</p>
<p>磁盘过滤驱动</p>
<p>-----------------------</p>
<p>disk.sys 类驱动</p>
<p>-----------------------</p>
<p><font color="#ff0000">miniport driver&nbsp;&nbsp;&nbsp;&nbsp; (实例sptd.sys cercsr6.sys)</font></p>
<p><font color="#ff0000"><font color="#000000">(miniport driver 调用 </font></font>port <font color="#000000">driver的函数,</font>scsiport.sys为port <font color="#000000">driver ,&nbsp;&nbsp;</font></p>
<p>deamo tool复制scsiport.sys为sptd0157.sys ,然后在sptd.sys中调用sptd0157.sys 的导出函数ScsiPortInitialize )</p>
<p>------------------------</p>
<p>磁盘</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>三 如何使用</p>
<p>1 做虚拟光驱已经实现了,不讲了</p>
<p>2 做还原卡 机器狗发irp 到disk.sys中然后分发到scsi miniport driver,</p>
<p>IRP_MJ_SCSI&nbsp;&nbsp; SCSI_REQUEST_BLOCK 这个在我们写的小端口驱动中判断重定位.....</p>
<p>3 做bootkit,可以先于windows系统加载, 在有anti rootkit 直接检测磁盘数据时可以进行欺骗</p>
<p>&nbsp;</p>
<p>最近的<a class="l" href="http://www2.gmer.net/mbr/" target="_blank"><font size="3"><u><font color="#cc0033">Stealth MBR</font><font color="#551a8b"> rootkit</font></u></font></a>被rku通过发IRP_MJ_SCSI检测/gmer通过Driver\Disk -&gt; MajorFunction[IRP_MJ_READ] = CLASSPNP!ClassReadWrite检测, 可以用miniport来让rku和gmer检不出来, miniport中HwStartIo处理传入的srb, 检查cdb中OperationCode 当为SCSIOP_READ和SCSIOP_WRITE的时候,判断扇区位置,如果是MBR则返回正确的mbr信息&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>研究时间比较短,大有错误之处,还请各位指正</p>
<p>参考文献</p>
<table class="tb" border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <div class="bword" style="line-height: 18px;">
            <p><font color="#000000">[1]水中雁 机器狗0625技术剖析（驱动读写磁盘扇区）</font><font color="#666666"><font color="#000000">水中雁 </font>2008-06-26 </font><a href="http://bbs.pediy.com/showthread.php?t=67321"><u><font color="#0000ff">http://bbs.pediy.com/showthread.php?t=67321</font></u></a></p>
            <p><font color="#666666">[2]&nbsp;&nbsp; <a href="http://www2.gmer.net/mbr/"><u><font color="#0000ff">http://www2.gmer.net/mbr/</font></u></a></font></p>
            <p><font color="#666666">[3]<a href="http://forums.microsoft.com/china/ShowPost.aspx?PostID=2727449&amp;SiteID=15"><u><font color="#0000ff">http://forums.microsoft.com/china/ShowPost.aspx?PostID=2727449&amp;SiteID=15</font></u></a></font></p>
            <p><font color="#666666">[4] 启动 <a href="http://knityster.javaeye.com/blog/172983"><u><font color="#0000ff">http://knityster.javaeye.com/blog/172983</font></u></a></font></p>
            </div>
            </td>
        </tr>
    </tbody>
</table><img src ="http://www.cppblog.com/momoxiao/aggbug/107340.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:19 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107340.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发送IRP删除正在运行文件学习笔记zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107339.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:18:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107339.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107339.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107339.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107339.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>在网上看到了北极星</span><span><font face="Times New Roman">2003</font></span><span>写的这篇文章，代码写的很好，注释也很清楚，方便了我这个大菜鸟的学习，对他的无私奉献非常非常感谢。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>强制删除文件的思路就是，把</span><span><font face="Times New Roman">SECTION_OBJECT_POINTERS</font></span><span>结构的</span><span><font face="Times New Roman">DataSectionObject</font></span><span>和</span><span><font face="Times New Roman">ImageSectionObject</font></span><span>两个域清空即可删除正在运行的文件。如果不清空就不能删除运行中的文件。正在运行的文件的这两个域值不为</span><span><font face="Times New Roman">0</font></span><span>而文件系统正在根据这两个域决定该文件是否可以删除。如果文件系统检测这两个值为</span><span><font face="Times New Roman">0</font></span><span>，就理解为文件没有被使用，可以删除。接下去，就是直接发</span><span><font face="Times New Roman">IRP,</font></span><span>初始化</span><span><font face="Times New Roman">IRP,</font></span><span>设置</span><span><font face="Times New Roman">IRP</font></span><span>堆栈信息，设置完成例程，派发</span><span><font face="Times New Roman">IRP</font></span><span>。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>一、获得文件内核句柄</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">RtlInitUnicodeString ( &amp;FileName, L&#8221; \\DosDevices\\C:\\test.exe&#8221; ) ;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">InitializeObjectAttributes ( &amp;objectAttributes, &amp;FileName,\</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt; text-indent: 110.25pt;"><span><font face="Times New Roman">OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, \</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt; text-indent: 110.25pt;"><span><font face="Times New Roman">NULL, NULL ) ;<span>&nbsp;&nbsp; </span></font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">ntStatus = IoCreateFile ( &amp;hFile,FILE_READ_ATTRIBUTES, &amp;objectAttributes, &amp;ioStatus, \</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_DELETE,FILE_OPEN,0,NULL,0,\</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt; text-indent: 42pt;"><span><font face="Times New Roman">CreateFileTypeNone,NULL, IO_NO_PARAMETER_CHECKING);</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>打开文件应该传入这个文件的路径。但是实际上这个函数</span><span><font face="Times New Roman">IoCreateFile</font></span><span>并不直接接受一个字符串。使用者必须首先填写一个</span><span><font face="Times New Roman">OBJECT_ATTRIBUTES </font></span><span>结构。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>用到一个宏：</span><span><font face="Times New Roman">InitializeObjectAttributes</font></span><span>用来初始化对象属性</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>我们是对</span><span><font face="Times New Roman">c:\test.exe</font></span><span>，这是个固定的文件了，属性应该也固定了，为什么还要初始化属性呢？</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>其实这里的初始化属性，主要是为了包含文件的对象路径，然后在指明该代码对该文件的一些要求，如获得内核句柄，不区分文件名的大小写，而不是对文件的操作。即将</span><span><font face="Times New Roman">FileName,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE</font></span><span>，全放入</span><span><font face="Times New Roman">objectAttributes</font></span><span>这个结构中。</span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">typedef struct _OBJECT_ATTRIBUTES {</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span>ULONG<span> </span>Length;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span>HANDLE<span> </span>RootDirectory;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span>PUNICODE_STRING<span> </span>ObjectName;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span>ULONG<span> </span>Attributes;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span>PVOID<span> </span>SecurityDescriptor;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span>PVOID<span> </span>SecurityQualityOfService;</font></span></p>
<p class="MsoNormal" style="background: none repeat scroll 0% 0% #f2f2f2; margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>要说明</span><span><font face="Times New Roman">2</font></span><span>点：</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">1</font></span><span>、</span><span><font face="Times New Roman">objectAttributes</font></span><span>结构中的</span><span><font face="Times New Roman">ObjectName</font></span><span>要求的是对象的路径名，因此不能写成</span><span><font face="Times New Roman">c:\test,</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">c:</font></span><span>是一个符号链接对象，内核模式下，符号链接要写成</span><span><font face="Times New Roman">\\??\\C:</font></span><span>或者</span><span><font face="Times New Roman">\\DosDevices\\C:</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>因此对象路径名为：</span><span><font face="Times New Roman">\\DosDevices\\C:\\test.exe</font></span><span>或</span><span><font face="Times New Roman">\\??\\C:\\test.exe</font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">2</font></span><span>、</span><span><font face="Times New Roman">InitializeObjectAttributes </font></span><span>只需要填写</span><span><font face="Times New Roman">OBJ_CASE_INSENSITIVE| OBJ_KERNEL_HANDLE</font></span><span>即可</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">OBJ_CASE_INSENSITIVE</font></span><span>意味着名字字符串是</span><font face="Times New Roman"> </font><span>不区分大小写的</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span><font face="Times New Roman">OBJ_KERNEL_HANDLE</font></span><span>表明打开的文件句柄一个&#8220;内核句柄&#8221;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>二、发送</span><span><font face="Times New Roman">IRP</font></span><span>去除文件的只读属性</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>对文件的任何操作，最终都是通过</span><span><font face="Times New Roman">IRP</font></span><span>请求，然后文件系统驱动对该</span><span><font face="Times New Roman">IRP</font></span><span>进行处理，完成对文件的指定操作。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>驱动程序，则可以自己创建</span><span><font face="Times New Roman">IRP</font></span><span>，初始化</span><span><font face="Times New Roman">IRP,</font></span><span>设置</span><span><font face="Times New Roman">IRP</font></span><span>堆栈信息，设置完成例程，派发</span><span><font face="Times New Roman">IRP</font></span><span>。这里我们采用的就是这种方法。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>三、发送</span><span><font face="Times New Roman">IRP</font></span><span>删除文件</span></p>
<span>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 20.9pt;"><span style="font-size: 9pt; color: black;">Windows API</span><span style="font-size: 9pt; color: black;">中的</span><span style="font-size: 9pt; color: black;">DeleteFile</span><span style="font-size: 9pt; color: black;">实现文件删除功能的内部实现：</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 20.9pt;"><span style="font-size: 9pt; color: black;">DeleteFile </span><span style="font-size: 9pt; color: black;">通过</span><span style="font-size: 9pt; color: black;"> IRP_MJ_SET_INFORMATION</span><span style="font-size: 9pt; color: black;">请求的</span><span style="font-size: 9pt; color: black;">IRP</span><span style="font-size: 9pt; color: black;">，并且将</span><span style="font-size: 9pt; color: black;">pIrpStack-&gt;Parameters.SetFile.FileInformationClass</span><span style="font-size: 9pt; color: black;">设为</span><strong><em><span style="font-size: 9pt; color: black;">FileDispositionInformation</span></em></strong><span style="font-size: 9pt; color: black;">且</span><span style="font-size: 9pt; color: black;">((PFILE_DISPOSITION_INFORMATION)Irp-&gt;AssociatedIrp.SystemBuffer)-&gt;DeleteFile</span><span style="font-size: 9pt; color: black;">设为</span><span style="font-size: 9pt; color: black;">TRUE</span><span style="font-size: 9pt; color: black;">来达到删除文件。</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 20.9pt;"><span style="font-size: 9pt; color: black;">所以我们有</span><span style="font-size: 9pt; color: black;">:</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">FILE_DISPOSITION_INFORMATION<span>&nbsp;&nbsp;&nbsp; </span>FileInformation;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">FileInformation.DeleteFile = TRUE;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">// </span><span style="font-size: 9pt; color: black;">初始化</span><span style="font-size: 9pt; color: black;">IRP<span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">Irp-&gt;AssociatedIrp.SystemBuffer<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>= &amp;FileInformation;<span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: black;">&#8230;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">// </span><span style="font-size: 9pt; color: black;">设置</span><span style="font-size: 9pt; color: black;">IRP</span><span style="font-size: 9pt; color: black;">堆栈</span><span style="font-size: 9pt; color: black;"><span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">irpSp-&gt;Parameters.SetFile.FileInformationClass<span>&nbsp;&nbsp; </span>= FileDispositionInformation;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: black;">&#8230;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 9pt; color: black;">由上，我们可以删除这个文件，但是如果文件在运行，则不能删除，需要加上如下代码：</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 9pt; color: black;">// </span><span style="font-size: 9pt; color: black;">如果没有这</span><span style="font-size: 9pt; color: black;">4</span><span style="font-size: 9pt; color: black;">行，就无法删除正在运行的文件</span><span style="font-size: 9pt; color: black;"><span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 9pt; color: black;">PSECTION_OBJECT_POINTERS<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pSectionObjectPointer;</span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: black;"><span>&nbsp;&nbsp;&nbsp; </span>pSectionObjectPointer = fileObject-&gt;SectionObjectPointer;<span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: black;"><span>&nbsp;&nbsp;&nbsp; </span>pSectionObjectPointer-&gt;ImageSectionObject = 0;<span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size: 9pt; color: black;"><span>&nbsp;&nbsp;&nbsp; </span>pSectionObjectPointer-&gt;DataSectionObject = 0;<span>&nbsp;&nbsp; </span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span>对于如何创建</span><span><font face="Times New Roman">IRP</font></span><span>，初始化</span><span><font face="Times New Roman">IRP,</font></span><span>设置</span><span><font face="Times New Roman">IRP</font></span><span>堆栈信息，设置完成例程，派发</span><span><font face="Times New Roman">IRP</font></span><span>，这里先不写了，等再整理整理后再写吧。</span></p>
</span><img src ="http://www.cppblog.com/momoxiao/aggbug/107339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:18 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对发送Irp删除文件的学习笔记zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107338.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:17:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107338.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107338.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107338.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107338.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107338.html</trackback:ping><description><![CDATA[<p>在网上逛游的时候，看到了<a href="http://blog.csdn.net/beijixing2003/archive/2008/06/11/2535069.aspx"><u><font color="#0000ff">http://blog.csdn.net/beijixing2003/archive/2008/06/11/2535069.aspx</font></u></a>这篇文章。于是对发送Irp删除文件进行了一翻学习。然后把代码重写了一下。上面链接的blog，把很多细节写的已经很详细了。所以学习起来还是很轻松的。</p>
<p>把自己重写的代码贴一下：</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">ntddk.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;AYA_DEVICE&nbsp;L"\\Device\\DFBSI"</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;AYA_LINK&nbsp;L"\\DosDevices\\DFBSI"</span><span style="color: #000000;"><br><br><br>HANDLE&nbsp;NTAPI&nbsp;AYA_OpenFile(&nbsp;IN&nbsp;PWCHAR&nbsp;szFileName&nbsp;)<br>{<br>NTSTATUS&nbsp;&nbsp;&nbsp;&nbsp;ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>UNICODE_STRING&nbsp;&nbsp;&nbsp;FileName;<br>OBJECT_ATTRIBUTES&nbsp;oa;<br>HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hFile;<br>IO_STATUS_BLOCK&nbsp;&nbsp;&nbsp;IoStatus;<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;KeGetCurrentIrql()&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;PASSIVE_LEVEL&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Irql&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;NULL;<br>}<br><br>RtlInitUnicodeString(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">FileName&nbsp;,szFileName&nbsp;);<br>InitializeObjectAttributes(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">oa&nbsp;,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">FileName&nbsp;,OBJ_CASE_INSENSITIVE&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;OBJ_KERNEL_HANDLE&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL&nbsp;,NULL);<br><br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoCreateFile(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">hFile&nbsp;,FILE_READ_ATTRIBUTES&nbsp;,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">oa&nbsp;,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">IoStatus&nbsp;,</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;,FILE_ATTRIBUTE_NORMAL&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE_SHARE_DELETE&nbsp;,FILE_OPEN&nbsp;,</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;,NULL&nbsp;,</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;,CreateFileTypeNone&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL&nbsp;,IO_NO_PARAMETER_CHECKING&nbsp;);<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(&nbsp;ns&nbsp;)&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ZwClose(&nbsp;hFile&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">IoCreateFile&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;NULL;<br>}<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;hFile;<br>}<br><br>NTSTATUS<br>IoSetFileCompletion(<br>&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PDEVICE_OBJECT&nbsp;DeviceObject,<br>&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PIRP&nbsp;Irp,<br>&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PVOID&nbsp;Context<br>&nbsp;&nbsp;&nbsp;&nbsp;)<br>{<br>Irp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserIosb</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Status&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Irp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">IoStatus.Status;<br>Irp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserIosb</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Information&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Irp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">IoStatus.Information;<br><br>KeSetEvent(&nbsp;Irp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserEvent&nbsp;,IO_NO_INCREMENT&nbsp;,FALSE&nbsp;);<br><br>IoFreeIrp(&nbsp;Irp&nbsp;);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;STATUS_MORE_PROCESSING_REQUIRED;<br>}<br><br><br>NTSTATUS&nbsp;NTAPI&nbsp;StripFileAttributes(&nbsp;IN&nbsp;HANDLE&nbsp;hFile&nbsp;)<br>{<br>NTSTATUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>PFILE_OBJECT&nbsp;&nbsp;&nbsp;&nbsp;pFileObject;<br>PDEVICE_OBJECT&nbsp;&nbsp;&nbsp;&nbsp;pDeviceObject;<br>PIRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pIrp;<br>KEVENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kFsEvent;<br>FILE_BASIC_INFORMATION&nbsp;FileInformation;<br>IO_STATUS_BLOCK&nbsp;&nbsp;&nbsp;&nbsp;IoStatus;<br>PIO_STACK_LOCATION&nbsp;&nbsp;&nbsp;pIrpSt;<br><br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ObReferenceObjectByHandle(&nbsp;hFile&nbsp;,DELETE&nbsp;,</span><span style="color: #000000;">*</span><span style="color: #000000;">IoFileObjectType&nbsp;,KernelMode&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(PVOID</span><span style="color: #000000;">*</span><span style="color: #000000;">)</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pFileObject&nbsp;,NULL&nbsp;);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(&nbsp;ns&nbsp;)&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ObReferenceObject(&nbsp;pFileObject&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">StripFileAttributes&nbsp;ObReferenceObjectByHandle&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br>}<br><br>pDeviceObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoGetRelatedDeviceObject(&nbsp;pFileObject&nbsp;);<br><br>pIrp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoAllocateIrp(&nbsp;pDeviceObject</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">StackSize&nbsp;,TRUE&nbsp;);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;pIrp&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;NULL&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ObReferenceObject(&nbsp;pFileObject&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">StripFileAttributes&nbsp;IoAllocateIrp&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;STATUS_UNSUCCESSFUL;<br>}<br><br>KeInitializeEvent(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">kFsEvent&nbsp;,SynchronizationEvent&nbsp;,FALSE&nbsp;);<br><br>RtlZeroMemory(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">FileInformation&nbsp;,</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(&nbsp;FILE_BASIC_INFORMATION&nbsp;)&nbsp;);<br>FileInformation.FileAttributes&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;FILE_ATTRIBUTE_NORMAL;<br><br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">AssociatedIrp.SystemBuffer&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">FileInformation;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserEvent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">kFsEvent;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserIosb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">IoStatus;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Tail.Overlay.Thread&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;PsGetCurrentThread();<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Tail.Overlay.OriginalFileObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">RequestorMode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;KernelMode;<br><br>pIrpSt&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoGetNextIrpStackLocation(&nbsp;pIrp&nbsp;);<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MajorFunction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IRP_MJ_SET_INFORMATION;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">DeviceObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pDeviceObject;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">FileObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Parameters.SetFile.Length&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(&nbsp;FILE_BASIC_INFORMATION&nbsp;);<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Parameters.SetFile.FileObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Parameters.SetFile.FileInformationClass<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;FileBasicInformation;<br><br>IoSetCompletionRoutine(&nbsp;pIrp&nbsp;,IoSetFileCompletion&nbsp;,NULL&nbsp;,TRUE&nbsp;,TRUE&nbsp;,TRUE&nbsp;);<br><br>IoCallDriver(&nbsp;pDeviceObject&nbsp;,pIrp&nbsp;);<br><br>KeWaitForSingleObject(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">kFsEvent&nbsp;,Executive&nbsp;,KernelMode&nbsp;,TRUE&nbsp;,NULL&nbsp;);<br><br>ObReferenceObject(&nbsp;pFileObject&nbsp;);<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>}<br><br><br>NTSTATUS&nbsp;NTAPI&nbsp;DeleteFileBySendIrp(&nbsp;IN&nbsp;HANDLE&nbsp;hFile&nbsp;)<br>{<br>NTSTATUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>PFILE_OBJECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFileObject;<br>PDEVICE_OBJECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pDeviceObject;<br>PIRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pIrp;<br>KEVENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kFsEvent;<br>FILE_DISPOSITION_INFORMATION&nbsp;FileInformation;<br>IO_STATUS_BLOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus;<br>PIO_STACK_LOCATION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pIrpSt;<br>PSECTION_OBJECT_POINTERS&nbsp;&nbsp;&nbsp;pSectionObjectPointer;<br><br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ObReferenceObjectByHandle(&nbsp;hFile&nbsp;,DELETE&nbsp;,</span><span style="color: #000000;">*</span><span style="color: #000000;">IoFileObjectType&nbsp;,KernelMode&nbsp;,\<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(PVOID</span><span style="color: #000000;">*</span><span style="color: #000000;">)</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pFileObject&nbsp;,NULL&nbsp;);<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(&nbsp;ns&nbsp;)&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ObReferenceObject(&nbsp;pFileObject&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">DeleteFileBySendIrp&nbsp;ObReferenceObjectByHandle&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br>}<br><br><br>pDeviceObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoGetRelatedDeviceObject(&nbsp;pFileObject&nbsp;);<br><br>pIrp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoAllocateIrp(&nbsp;pDeviceObject</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">StackSize&nbsp;,TRUE&nbsp;);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;pIrp&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;NULL&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ObReferenceObject(&nbsp;pFileObject&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">DeleteFileBySendIrp&nbsp;IoAllocateIrp&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;STATUS_UNSUCCESSFUL;<br>}<br><br>KeInitializeEvent(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">kFsEvent&nbsp;,SynchronizationEvent&nbsp;,FALSE&nbsp;);<br><br>FileInformation.DeleteFile&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;TRUE;<br><br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">AssociatedIrp.SystemBuffer&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">FileInformation;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserEvent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">kFsEvent;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">UserIosb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">IoStatus;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Tail.Overlay.Thread&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;PsGetCurrentThread();<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Tail.Overlay.OriginalFileObject&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject;<br>pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">RequestorMode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;KernelMode;<br><br>pIrpSt&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoGetNextIrpStackLocation(&nbsp;pIrp&nbsp;);<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MajorFunction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IRP_MJ_SET_INFORMATION;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">DeviceObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pDeviceObject;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">FileObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Parameters.SetFile.Length&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(&nbsp;FILE_DISPOSITION_INFORMATION&nbsp;);<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Parameters.SetFile.FileObject&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject;<br>pIrpSt</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">Parameters.SetFile.FileInformationClass<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;FileDispositionInformation;<br>IoSetCompletionRoutine(&nbsp;pIrp&nbsp;,IoSetFileCompletion&nbsp;,NULL&nbsp;,TRUE&nbsp;,TRUE&nbsp;,TRUE&nbsp;);<br><br>pSectionObjectPointer&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFileObject</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">SectionObjectPointer;<br>pSectionObjectPointer</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">DataSectionObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>pSectionObjectPointer</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">ImageSectionObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br><br>IoCallDriver(&nbsp;pDeviceObject&nbsp;,pIrp&nbsp;);<br><br>KeWaitForSingleObject(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">kFsEvent&nbsp;,Executive&nbsp;,KernelMode&nbsp;,TRUE&nbsp;,NULL&nbsp;);<br><br>ObReferenceObject(&nbsp;pFileObject&nbsp;);<br><br>KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">OK</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>}<br><br>NTSTATUS&nbsp;NTAPI&nbsp;ForceDeleteFiles(&nbsp;PWCHAR&nbsp;szFileName&nbsp;)<br>{<br>HANDLE&nbsp;&nbsp;&nbsp;&nbsp;hFile;<br>NTSTATUS&nbsp;&nbsp;&nbsp;ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br><br>hFile&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;AYA_OpenFile(&nbsp;szFileName&nbsp;);<br><br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;StripFileAttributes(&nbsp;hFile&nbsp;);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(&nbsp;ns&nbsp;)&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ZwClose(&nbsp;hFile&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">ForceDeleteFiles&nbsp;StripFileAttributes&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br>}<br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;DeleteFileBySendIrp(&nbsp;hFile&nbsp;);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(&nbsp;ns&nbsp;)&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;ZwClose(&nbsp;hFile&nbsp;);<br>&nbsp;&nbsp;&nbsp;KdPrint((&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">ForceDeleteFiles&nbsp;DeleteFileBySendIrp&nbsp;Error</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;));<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br>}<br>ZwClose(&nbsp;hFile&nbsp;);<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br>}<br><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;AYA_Unload(&nbsp;IN&nbsp;PDRIVER_OBJECT&nbsp;pDriverObj&nbsp;)<br>{<br>UNICODE_STRING&nbsp;Temp;<br><br>RtlInitUnicodeString(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">Temp&nbsp;,AYA_LINK&nbsp;);<br>IoDeleteSymbolicLink(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">Temp&nbsp;);<br>IoDeleteDevice(&nbsp;pDriverObj</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">DeviceObject&nbsp;);<br>}<br><br>NTSTATUS&nbsp;AYA_Dispatch(&nbsp;IN&nbsp;PDEVICE_OBJECT&nbsp;pDeviceObj&nbsp;,IN&nbsp;PIRP&nbsp;pIrp&nbsp;)<br>{<br>NTSTATUS&nbsp;ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>PIO_STACK_LOCATION&nbsp;stIrp;<br><br>stIrp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoGetCurrentIrpStackLocation(&nbsp;pIrp&nbsp;);<br><br></span><span style="color: #0000ff;">switch</span><span style="color: #000000;">(&nbsp;stIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MajorFunction&nbsp;)<br>{<br></span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;IRP_MJ_CREATE:<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;IRP_MJ_CLOSE:<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;IRP_MJ_DEVICE_CONTROL:<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">default</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">IoStatus.Status&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_INVALID_PARAMETER;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>}<br><br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pIrp</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">IoStatus.Status;<br>IoCompleteRequest(&nbsp;pIrp&nbsp;,IO_NO_INCREMENT&nbsp;);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br>}<br><br>NTSTATUS&nbsp;DriverEntry(&nbsp;IN&nbsp;PDRIVER_OBJECT&nbsp;pDriverObj&nbsp;,IN&nbsp;PUNICODE_STRING&nbsp;RegistryPath&nbsp;)<br>{<br>NTSTATUS&nbsp;&nbsp;&nbsp;ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;STATUS_SUCCESS;<br>UNICODE_STRING&nbsp;AYA;<br>UNICODE_STRING&nbsp;AYAL;<br>PDEVICE_OBJECT&nbsp;pDevice;<br>WCHAR&nbsp;&nbsp;&nbsp;&nbsp;szFileName[]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;L</span><span style="color: #000000;">"</span><span style="color: #000000;">\\??\\C:\\2.txt</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br><br>RtlInitUnicodeString(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">AYA&nbsp;,AYA_DEVICE&nbsp;);<br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoCreateDevice(&nbsp;pDriverObj&nbsp;,</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">AYA&nbsp;,FILE_DEVICE_UNKNOWN&nbsp;,</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;,FALSE&nbsp;,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pDevice&nbsp;);<br><br>RtlInitUnicodeString(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">AYAL&nbsp;,AYA_LINK&nbsp;);<br>ns&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoCreateSymbolicLink(&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">AYAL&nbsp;,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">AYA&nbsp;);<br><br>pDriverObj</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MajorFunction[IRP_MJ_CREATE]&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;<br>pDriverObj</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MajorFunction[IRP_MJ_CLOSE]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;"><br>pDriverObj</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MajorFunction[IRP_MJ_DEVICE_CONTROL]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;AYA_Dispatch;<br><br>pDriverObj</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">DriverUnload&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;AYA_Unload;<br><br>ForceDeleteFiles(&nbsp;szFileName&nbsp;);<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ns;<br><br>}<br></span></div><img src ="http://www.cppblog.com/momoxiao/aggbug/107338.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:17 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107338.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>请教：diskperf过滤驱动改装隐藏磁盘容量的问题。zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107337.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:16:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107337.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107337.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107337.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107337.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107337.html</trackback:ping><description><![CDATA[目前想隐藏硬盘最后一部分容量，即最后一部分对系统不可见。<br>现在假设让系统只能看到前1/2的容量，包括各种在Windows系统上运行的分区软件。<br>在diskperf中DbgPrint看到系统刷新磁盘信息时只调用了下列IO Control<br>IOCTL_DISK_GET_DRIVE_GEOMETRY<br>IOCTL_DISK_GET_DRIVE_LAYOUT<br>IOCTL_DISK_GET_DRIVE_LAYOUT_EX<br>IOCTL_DISK_GET_PARTITION_INFO_EX<br>IOCTL_SCSI_GET_ADDRESS<br>IOCTL_STORAGE_GET_DEVICE_NUMBER<br>IOCTL_STORAGE_GET_HOTPLUG_INFO<br>IOCTL_STORAGE_GET_MEDIA_TYPES_EX<br>IOCTL_STORAGE_PREDICT_FAILURE<br>IOCTL_STORAGE_QUERY_PROPERTY<br><br>我现在的做法是用diskperf来过滤，在<br>IOCTL_DISK_GET_DRIVE_GEOMETRY<br>IOCTL_STORAGE_GET_MEDIA_TYPES_EX<br>IOCTL_DISK_GET_LENGTH_INFO<br>IOCTL_DISK_GET_DRIVE_GEOMETRY_EX<br>IOCTL_DISK_GET_MEDIA_TYPES<br>IOCTL_STORAGE_GET_MEDIA_TYPES<br>IOCTL_STORAGE_GET_MEDIA_TYPES_EX<br>中将Cylinders减半。<br><br>现在用运行于Windows上的Partition Magic已经只能看都磁盘容量减半了，<br>但Windows自带的磁盘管理员(diskmgmt.msc)却还是看到原有的容量。<br>（大致看了一下，磁盘管理员好像是调用本机的Logical Disk Manager Administrative Service这个DCOM组件来读取信息的,<br>用Depends查看了这个DCOM组件程序dmadmin.exe，他也调用了DeviceIoControl，但不知他是否还从别的途径拿磁盘信息了？）<br>请问各位兄弟有做过类似的东西吗？<br>我需要如何才能让磁盘管理员也看到我减半后的容量？<br>------------------------------------------------------------------------------------<br>这个问题我已解决了。<br>Windows自带的磁盘管理器是用IOCTL_DISK_GET_PARTITION_INFO /I OCTL_DISK_GET_PARTITION_INFO_EX来确定磁盘大小的。<br>因此还需要在diskperf的DeviceIoControl中修改对磁盘本身（\Device\Harddisk0\DR0之类，也就是Partition0）所执行的IOCTL_DISK_GET_PARTITION_INFO /I OCTL_DISK_GET_PARTITION_INFO_EX返回值。<br>------------------------------------------------------------------------------------<br><img src ="http://www.cppblog.com/momoxiao/aggbug/107337.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:16 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107337.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于WinDbg 设置断点的问题zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107336.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:15:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107336.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107336.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107336.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107336.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107336.html</trackback:ping><description><![CDATA[<p>基础知识</p>
<p>bp 程序运行过程中下断点</p>
<p>bu 程序未加载之前下断点</p>
<p>bl&nbsp; 列出所有断点</p>
<p>bc&nbsp; 清除断点</p>
<p>今天在调试驱动的时候 发现下好断点后 无法调试</p>
<p>WinDbg显示</p>
<p>kd&gt; g<br>Breakpoint 11's offset expression evaluation failed.<br>Check for invalid symbols or bad syntax.<br>WaitForEvent failed<br>nt!DebugService2+0x11:</p>
<p><br>按照字面的理解意思就是11号断点有问题</p>
<p>于是 上网找WinDbg的相关操作说明</p>
<p>找到了一点东西&nbsp; 就是上面的基础知识</p>
<p>下面说说解决过程</p>
<p>首先</p>
<p>kd&gt; bl<br>&nbsp;0 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (@@masm(`HelloDDK!Driver.cpp:35+`))<br>&nbsp;1 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (HelloDDK!DriverEntry)<br>&nbsp;2 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (HelloDDK!DriverEntry)<br>&nbsp;3 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (HelloDDK!DriverEntry)<br>&nbsp;4 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>&nbsp;5 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (HelloDDK!DriverEntry)<br>&nbsp;6 e f9ed4900&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!CreateDevice<br>&nbsp;7 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (Test!DriverEntry)<br>&nbsp;8 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (Driver!DriverEntry)<br>&nbsp;9 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (@@masm(`Driver.cpp:18+`))<br>10 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>11 eu&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) (MyDDK!lCreateFile)<br>12 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>13 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>14 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>15 e f9ed48ad&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry+0x1d</p>
<p><br>发现有很多地方没有地址&nbsp; 应该是这些地方的断点有问题&nbsp; 删除之</p>
<p><br>kd&gt; bc 0 1 2 3 5 7 8 9<br>kd&gt; bl<br>&nbsp;4 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>&nbsp;6 e f9ed4900&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!CreateDevice<br>10 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>12 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>13 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>14 e f9ed4890&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry<br>15 e f9ed48ad&nbsp;&nbsp;&nbsp;&nbsp; 0001 (0001) MyDDK!DriverEntry+0x1d </p>
<p>再继续</p>
<p>kd&gt; g<br>可以运行</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/lijiawlm/archive/2009/08/05/4412289.aspx">http://blog.csdn.net/lijiawlm/archive/2009/08/05/4412289.aspx</a></p><img src ="http://www.cppblog.com/momoxiao/aggbug/107336.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:15 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107336.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows内核学习笔记（六）-- [总结]创建IRP的四种不同方式zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107334.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:13:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107334.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107334.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107334.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107334.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107334.html</trackback:ping><description><![CDATA[<p>在驱动程序中，经常会调用其他的驱动程序；其中，手动构造 IRP ，然后将 IRP 传递到相应驱动程序的派遣函数中是一种比较简单的方法，下面就来介绍下手动创建 IRP 的几种不同的方法及其特点。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建 IRP 总共有 4 种方法。分别通过调用： IoBuildSynchronousFsdRequest 、 IoBuildAsynchronousFsdRequest 、 IoBuildDeviceIoControl 和 IoAllocateIrp 这 4 个内核函数来完成。这其中， IoAllocateIrp 是比较底层的内核函数，其余的三个内核函数是属于靠近上层的内核函数，而且这三个函数都是通过调用 IoAllocateIrp 实现的。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这几个函数都是文档化的函数，原型都可以在 DDK Documentation 中查到，这里就不多说了，下面主要来说说它们的不同点： </p>
<p>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可创建的 IRP 类型 </p>
<p>这四个函数可以创建的 IRP 的类型是不同的。 IoBuildSynchronousFsdRequest 用于创建同步的 IRP 请求，但是只可以创建以下类型的 IRP ： IRP_MJ_PNP ,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_FLUSH_BUFFERS 和IRP_MJ_SHUTDOWN ； IoBuildAsynchronousFsdRequest 可创建的 IRP 类型和 IoBuildSynchronousFsdRequest 一样（从名字就可以看出来），只是它是用来创建异步的 IRP 请求。 IoBuildDeviceIoControl 可以创建的 IRP 类型为：IRP_MJ_DEVICE_CONTROL 和IRP_MJ_INTERNAL_DEVICE_CONTROL 。而且 IoBuildDeviceIoControl 只能创建同步的 IRP 。在这三个函数中，都有一个 ULONG 的输入参数指定创建的 IRP 类型。 IoAllocateIrp 函数的使用比较灵活，他可以创建任意类型的 IRP ，但不是由参数指定，而是创建后自行填写，要求用户对 IRP 的结构有比较熟悉的理解。 </p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建后 IRP 对象的删除 </p>
<p>IoBuildSynchronousFsdRequest 、 IoBuildAsynchronousFsdRequest 和 IoBuildDeviceIoControl 内核函数在创建完 IRP 后，不需要程序员负责删除 IRP ，操作系统会自动删除。而用 IoAllocateIrp 内核函数创建 IRP 时，需要程序员自己调用 IoFreeIrp 内核函数删除 IRP 对象。 </p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关联的事件 </p>
<p>IoBuildSynchronousFsdRequest 和 IoBuildDeviceIoControl 在创建 IRP 时，需要为它们准备好一个事件，这个事件会和 IRP 请求相关联，当 IRP 请求被结束时该事件触发。程序中要用 KeWaitForSingleObject 函数等待。 IoBuildAsynchronousFsdRequest 函数创建 IRP 时则不需要准备事件，不过可以通过 IRP 的 UserEvent 子域来通知 IRP 请求的结束。 </p>
<p>当执行 IoCompleteRequest 内核函数时，操作系统会检查 IRP 的 UserEvent 子域是否为空。如果该子域为空，则它代表一个事件指针，这时 IoCompleteRequest 会设置这个事件。 </p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/vangoals/archive/2009/07/26/4381567.aspx">http://blog.csdn.net/vangoals/archive/2009/07/26/4381567.aspx</a></p><img src ="http://www.cppblog.com/momoxiao/aggbug/107334.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:13 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107334.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战DeviceIoControl之三：制作磁盘镜像文件</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107333.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:12:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107333.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107333.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107333.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107333.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107333.html</trackback:ping><description><![CDATA[<strong><font size="5">Q</font></strong> DOS命令DISKCOPY给我很深的印象，现在也有许多&#8220;克隆&#8221;<a class="UBBWordLink" href="http://www.ahaoz.com/" target="_blank"><font color="#000080">软件</font></a>，可以对磁盘进行全盘复制。我想，要制作磁盘镜像文件，DeviceIoControl应该很有用武之地吧？
<p><font size="5"><strong>A</strong></font> 是的。这里举一个制作软盘镜像文件，功能类似于&#8220;DISKCOPY&#8221;的例子。<br>本例实现其功能的核心<a class="UBBWordLink" href="http://www.ahaoz.com/" target="_blank"><font color="#000080">代码</font></a>如下：</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;打开磁盘</span><span style="color: #008000;"><br></span><span style="color: #000000;">HANDLE&nbsp;OpenDisk(LPCTSTR&nbsp;filename)<br>{<br>&nbsp;HANDLE&nbsp;hDisk;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;打开设备</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;hDisk&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::CreateFile(filename,&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;文件名</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;GENERIC_READ&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;GENERIC_WRITE,&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;读写方式</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;FILE_SHARE_READ&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;FILE_SHARE_WRITE,&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;共享方式</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;默认的安全描述符</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;OPEN_EXISTING,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;创建方式</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需设置文件属性</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需参照模板文件</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;hDisk;<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;获取磁盘参数</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;GetDiskGeometry(HANDLE&nbsp;hDisk,&nbsp;PDISK_GEOMETRY&nbsp;lpGeometry)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwOutBytes;<br>&nbsp;BOOL&nbsp;bResult;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;bResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::DeviceIoControl(hDisk,&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;设备句柄</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;IOCTL_DISK_GET_DRIVE_GEOMETRY,&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;取磁盘参数</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输入数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;lpGeometry,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(DISK_GEOMETRY),&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据缓冲区</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">dwOutBytes,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据长度</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;(LPOVERLAPPED)NULL);&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用同步I/O</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;bResult;<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;从指定磁道开始读磁盘</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;ReadTracks(HANDLE&nbsp;hDisk,&nbsp;PDISK_GEOMETRY&nbsp;lpGeometry,&nbsp;LPVOID&nbsp;pBuf,&nbsp;DWORD&nbsp;dwStartCylinder,&nbsp;DWORD&nbsp;<br><br>dwCylinderNumber)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;VirtBufSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;BytesRead;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;大小</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;VirtBufSize&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">TracksPerCylinder&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">SectorsPerTrack&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">BytesPerSector;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;偏移</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;::SetFilePointer(hDisk,&nbsp;VirtBufSize</span><span style="color: #000000;">*</span><span style="color: #000000;">dwStartCylinder,&nbsp;NULL,&nbsp;FILE_BEGIN);<br><br>&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;::ReadFile(hDisk,&nbsp;pBuf,&nbsp;VirtBufSize</span><span style="color: #000000;">*</span><span style="color: #000000;">dwCylinderNumber,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">BytesRead,&nbsp;NULL);<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;从指定磁道开始写磁盘</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;WriteTracks(HANDLE&nbsp;hDisk,&nbsp;PDISK_GEOMETRY&nbsp;lpGeometry,&nbsp;LPVOID&nbsp;pBuf,&nbsp;DWORD&nbsp;dwStartCylinder,&nbsp;DWORD&nbsp;<br><br>dwCylinderNumber)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;VirtBufSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;BytesWritten;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;大小</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;VirtBufSize&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">TracksPerCylinder&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">SectorsPerTrack&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">BytesPerSector;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;偏移</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;::SetFilePointer(hDisk,&nbsp;VirtBufSize</span><span style="color: #000000;">*</span><span style="color: #000000;">dwStartCylinder,&nbsp;NULL,&nbsp;FILE_BEGIN);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;::WriteFile(hDisk,&nbsp;pBuf,&nbsp;VirtBufSize</span><span style="color: #000000;">*</span><span style="color: #000000;">dwCylinderNumber,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">BytesWritten,&nbsp;NULL);<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;从指定磁道开始格式化磁盘</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;LowLevelFormatTracks(HANDLE&nbsp;hDisk,&nbsp;PDISK_GEOMETRY&nbsp;lpGeometry,&nbsp;DWORD&nbsp;dwStartCylinder,&nbsp;DWORD&nbsp;<br><br>dwCylinderNumber)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;FORMAT_PARAMETERS&nbsp;FormatParameters;<br>&nbsp;&nbsp;&nbsp;&nbsp;PBAD_TRACK_NUMBER&nbsp;lpBadTrack;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwOutBytes;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwBufSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bResult;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;FormatParameters.MediaType&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">MediaType;<br>&nbsp;&nbsp;&nbsp;&nbsp;FormatParameters.StartCylinderNumber&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;dwStartCylinder;<br>&nbsp;&nbsp;&nbsp;&nbsp;FormatParameters.EndCylinderNumber&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;dwStartCylinder&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;dwCylinderNumber&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;FormatParameters.StartHeadNumber&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;FormatParameters.EndHeadNumber&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">TracksPerCylinder&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;dwBufSize&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lpGeometry</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">TracksPerCylinder&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(BAD_TRACK_NUMBER);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;lpBadTrack&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(PBAD_TRACK_NUMBER)&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;BYTE[dwBufSize];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用IOCTL_DISK_FORMAT_TRACKS对连续磁道进行低级格式化</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;bResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::DeviceIoControl(hDisk,&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;设备句柄</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;IOCTL_DISK_FORMAT_TRACKS,&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;低级格式化</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">FormatParameters,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(FormatParameters),&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输入数据缓冲区</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;lpBadTrack,&nbsp;dwBufSize,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据缓冲区</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">dwOutBytes,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据长度</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;(LPOVERLAPPED)NULL);&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用同步I/O</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;lpBadTrack;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;bResult;<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;将卷锁定</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;LockVolume(HANDLE&nbsp;hDisk)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwOutBytes;<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bResult;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用FSCTL_LOCK_VOLUME锁卷</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;bResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::DeviceIoControl(hDisk,&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;设备句柄</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;FSCTL_LOCK_VOLUME,&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;锁卷</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输入数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输出数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">dwOutBytes,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据长度</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;(LPOVERLAPPED)NULL);&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用同步I/O</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;bResult;<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;将卷解锁</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;UnlockVolume(HANDLE&nbsp;hDisk)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwOutBytes;<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bResult;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用FSCTL_UNLOCK_VOLUME开卷锁</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;bResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::DeviceIoControl(hDisk,&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;设备句柄</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;FSCTL_UNLOCK_VOLUME,&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;开卷锁</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输入数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输出数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">dwOutBytes,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据长度</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;(LPOVERLAPPED)NULL);&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用同步I/O</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;bResult;<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;将卷卸下<br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;该操作使系统重新辨识磁盘，等效于重新插盘</span><span style="color: #008000;"><br></span><span style="color: #000000;">BOOL&nbsp;DismountVolume(HANDLE&nbsp;hDisk)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwOutBytes;<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bResult;<br><br>&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用FSCTL_DISMOUNT_VOLUME卸卷</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;bResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;::DeviceIoControl(hDisk,&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;设备句柄</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;FSCTL_DISMOUNT_VOLUME,&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;卸卷</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输入数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;NULL,&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;不需要输出数据</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">dwOutBytes,&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;输出数据长度</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;(LPOVERLAPPED)NULL);&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;用同步I/O</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;bResult;<br>}<br></span></div>
<p>将软盘保存成镜像文件的步骤简单描述为：<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>将镜像文件载入软盘的步骤简单描述为：<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><br>Q 我注意到，磁盘读写和格式化是按柱面进行的，有什么道理吗？</p>
<p>A 没有特别的原因，只是因为在这个例子中可以方便地显示处理进度。<br>有一点需要特别提及，按绝对地址读写磁盘数据时，&#8220;最小单位&#8221;是扇区，地址一定要与扇区对齐，长度也要等于扇区长度的整数倍。比如，每扇区512字节，那么起始地址和数据长度都应能被512整除才行。</p>
<p><br>Q 我忽然产生了一个伟大的想法，用绝对地址读写的方式使用磁盘，包括U盘啦，MO啦，而不是用现成的文件系统，那不是可以将数据保密了吗？</p>
<p>A 当然，只要你喜欢。可千万别在你的系统盘上做试验，否则......可别怪bhw98没有提醒过你喔！</p>
<p><br>Q 我知道怎么测试光驱的传输速度了，就用上面的方法，读出一定长度数据，除以所需时间，应该可以吧？</p>
<p>A 可以。但取光盘参数时要用IOCTL_STORAGE_GET_MEDIA_TYPES_EX，我们已经探讨过的。 </p><img src ="http://www.cppblog.com/momoxiao/aggbug/107333.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:12 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我们一起讨论把驱动自动安装的问题搞定搞清楚好吗？zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107332.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:08:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107332.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107332.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107332.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107332.html</trackback:ping><description><![CDATA[<a href="http://bbs.driverdevelop.com/simple/index.php?t65230.html">http://bbs.driverdevelop.com/simple/index.php?t65230.html</a><br>----------------------<br>关于驱动程序安装，只要你细心看了ddk,就应该知道怎样作 <br>对于即插即用简单地说要对付2种情况 <br>1。在你的设备未安装前，安装驱动程序这叫预先安装。 <br>最简单的方法就是使用SetupCopyOEMInf函数。 <br><br>具体做法是： <br>将SetupCopyOEMInf封装在一个动态库里。 <br>用installshield将所有文件copy到一个临时目录。 <br>调用动态库使用SetupCopyOEMInf函数copy临时目录下的inf文件（路径）。 <br>installshield让计算机重启。 <br><br>插上设备，自动识别。 <br><br>2.你的设备已安装，弹出安装向导。 <br>很简单，让用户搜索你的安装盘，即可完成安装。 <br><br>我认为，没有特别必要的情况下，没必要使用coinstall. <br>对与非即插即用设备，要区别对待。<br>----------------------------------------------------------------------------------------<br><br>关于打印机的安装： <br>非即插即用，如并口。 <br>1。使用添加打印向导，简单的不能再简单了。 <br>2。将AddPrinter,AddPrinterDriver,AddMonitor等封装在动态库。 <br>使用installshield制作安装copy必要的文件到指定的目录。然后调用这个动态库里的这些函数。祥见ddk. <br><br>即插即用如usb <br>和通用即插即用安装方法类似。 <br>ddk里有详细的说明。 <br>重要的一点，在你的固件（firmware),响应IOCTL_GET_DEVICE_ID时 <br>返回IEEE1284兼容的设备ID，格式详见sdk. <br>关于详细的标准，请查阅usb工作组的设备类规范。 <br><br>这些是关于即插即用的安装，大多数情况不必修改注册表，对于老式nt的程序则需要。 <br>其实在注册表里添加东西不必大费周张，很简单，installshield就支持对注册表的任意修改。不必用什么函数，即改即用，方便。<br>----------------------------------------------------<br>关于扫描仪和照相机的安装 <br>1.非即插即用如串口。 <br>a.可以使用安装向导。 <br>b.installshiel或coinstall <br>2.即插即用如usb <br>同前面的即插即用安装一样。 <br><br>扫描仪和照相机多出的是接口数据源的安装，如twaince。 <br><img src ="http://www.cppblog.com/momoxiao/aggbug/107332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:08 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>usb驱动自安装程序的制作zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107331.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:06:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107331.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107331.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107331.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107331.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107331.html</trackback:ping><description><![CDATA[这两天询问usb驱动安装程序制作的人很多，我有幸做成过一个这样的安装程序。虽然这两天测试也有人回复说还有问题，但我还是对我的安装程序充满信心。 <br><br>我也曾在本论坛回答过一些朋友的帖子，但回复成功的似乎还没有。这也很正常，毕竟影响安装的因素太多。 <br><br>我现在简单介绍一下usb驱动安装程序的制作过程，希望能给有这方面需求的朋友一点启示，也希望这方面的大拿能给与批评指正。 <br><br><br>1，准备inf和sys <br>新建一个目录，比如d:\\DrvInstDir，把你写好的inf和sys都放在此目录下。 <br><br>2，验证你的inf <br>把系统清理干净，就如同你从来没在这台机器上装过你的驱动程序一样。然后，手工安装你的设备，验证用你的inf是否能正确安装你的sys。注意，这儿有特殊要求，就是在安装过程中，指定了d:\\DrvInstDir为搜寻目录之后，系统就能自动找到sys文件并执行安装，而不会再要求你指定sys文件的位置。如果你的inf满足此要求，则第二步通过；否则请修改你的inf文件，直到它能满足要求为止。 <br><br>3，编写安装程序 <br>简单做的话，只需调用SetupCopyOEMInf即可。比如： <br>SetupCopyOEMInf("d:\\\\DrvInstDir\\\\xxxx.inf",NULL,SPOST_PATH,0,NULL,0,NULL,NULL)； <br><br>4，再次将系统清理干净 <br><br>5，运行安装程序 <br>SetupCopyOEMInf会在%windir%\\inf目录下生成一个oem*.inf。找找看有没有跟你的inf内容完全一致的oem*.inf，如果有，则成功，可以继续往下走。否则，请退回到前面，察看哪儿出了问题。 <br><br>6，插上usb设备，验证安装程序是否生效 <br>注意，在2k下，插上usb设备后，如果设备硬件id和inf中的硬件id完全匹配（注意，如果是其他匹配形式，比如设备硬件id匹配inf中的兼容id或者设备兼容id匹配inf中的硬件id，那么我不保证上述方法有效），那么系统会自动将sys文件从d:\\DrvInstDir下复制到%windir%\\System32\\Drivers目录下，并对其进行安装。如果在xp下，且inf和sys没有经过数字签名，那么系统会弹出&#8220;发现新硬件&#8221;窗口，你只需连续点击窗口上的&#8220;下一步&#8221;按钮即可完成驱动程序的安装。至于在xp下，如何避免inf和sys未经数字签名时系统弹出&#8220;发现新硬件&#8221;窗口，并让系统自动完成设备驱动程序的安装，请参考我在本论坛发的&#8220;协作安装程序应用一例&#8221;一帖。 <br><img src ="http://www.cppblog.com/momoxiao/aggbug/107331.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:06 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107331.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>协作安装程序应用一例 (欢迎进来瞧瞧！)zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107330.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107330.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107330.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107330.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107330.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107330.html</trackback:ping><description><![CDATA[所谓&#8220;协作安装程序&#8221;，在ddk文档里面称作co-installer，有人将它翻译成&#8220;共同安装程序&#8221;。但是， <br>从ddk文档对co-installer功能的描述来看，我个人觉得翻译成&#8220;协作安装程序&#8221;更恰当些。 <br><br>ddk文档对co-installer的描述：A co-installer is a Microsoft&#174; Win32&#174; DLL that assists in <br>device installation. Co-installers are called by Setup API as "helpers" for Class <br>Installers.简单地翻译一下：协作安装程序是一个Win32 DLL,它辅助设备的安装。协作安装程序 <br>由Setup API调用，作为类安装程序的&#8220;助手&#8221;。 <br><br>在本论坛搜索了一下有关&#8220;协作安装程序&#8221;的帖子，发现这方面的帖子很少。我想之所以这样，是因为 <br>大家在驱动开发过程中可能很少有需要用到协作安装程序的地方。或者说本来有些地方可以使用，但可能 <br>因为不太了解这方面的东西，所以没有想到去用它。 <br><br>这儿，我想介绍一个关于协作安装程序的应用实例。 <br><br>开发过USB设备驱动的朋友，不知有没有碰到过下面的问题：如果你的设备驱动程序没有经过数字签名， <br>那么，在XP系统下，你在每个USB口上第一次插上你的USB设备时，系统都会要求你装一次驱动程序。 <br>这种感觉是很不好的。我们希望能像大多数USB移动盘一样，插上设备就自动安装驱动，然后就可以对 <br>设备进行访问了。 <br><br>如何让我们的USB设备插上后，系统也能自动为它安装驱动，而不需要烦劳用户手动安装呢？解决此问题 <br>的核心技术在于编写一个类协作安装程序。 <br><br>首先，有一个问题大家要清楚，USB设备第一次插到机器上的一个USB口上时，系统要为它 <br>装一次驱动程序。我们以USB设备为例，来了解一下支持热插拔的PnP设备的安装过程： <br>（1）设备插入系统，USB总线驱动向内核PnP管理器报告有新设备接入系统； <br>（2）内核PnP管理器向USB总线驱动询问设备的具体信息，比如PID和VID等； <br>（3）内核PnP管理器将设备的信息报告给用户层的PnP管理器，并要求它为新设备安装驱动； <br>（4）用户层PnP管理器调用系统的Setup组件来为设备安装驱动； <br>（5）Setup使用设备VID和PID到%Windir%\\inf下寻找适合它的inf文件，并获得一个可用于设备的驱动程序列表； <br>（6）Setup在生成驱动程序列表的时候，会检查inf文件是否经过数字签名，如果没有经过数字签名， <br>Setup会将此inf文件负责安装的驱动程序设置成&#8220;不可信任的&#8221;驱动程序； <br>（7）Setup对驱动程序列表中的各驱动程序信息进行分析，选择最匹配设备的驱动程序进行安装； <br><br>这里，有必要提一下&#8220;不可信任的驱动程序&#8221;这个概念。这个概念在xp之后才有的，2k和98没有。在Setup <br>生成的驱动程序列表中，每个驱动程序的信息结构中都有一个Rank字段。在xp中，0x0 &lt; Rank &lt;= 0x3FFF的 <br>驱动程序被认为是&#8220;可信任的&#8221;；0x8000 &lt;= Rank &lt;= 0xFFFF的驱动被认为是&#8220;不可信任的&#8221;。如果我们的 <br>驱动程序没有经过数字签名，那么它的Rank值肯定落在0x8000到0xFFFF之间。 <br><br>再回到前面的安装过程，如果驱动程序中有适合设备的&#8220;可信任&#8221;驱动程序，那么系统自动对它进行安装； <br>如果驱动程序列表中的所有驱动程序都是&#8220;不可信任的&#8221;，那么系统就会弹出&#8220;发现新硬件&#8221;向导，要你提 <br>供更好的驱动程序，或者要你确认安装&#8220;不可信任的&#8221;驱动程序。这就是为什么在xp系统下，即便你在一个 <br>USB口上已经安装了设备的驱动程序，你再换个口插上设备，系统又会提示你安装驱动程序的原因。 <br><br>说了半天，我想现在各位肯定都明白过来了：影响设备驱动程序自动安装的主要原因，是因为我们的 <br>驱动程序被系统认为是&#8220;不可信任的&#8221;。而系统判断一个驱动程序是否&#8220;可信任&#8221;，是通过驱动程序信息结 <br>构中的Rank字段的值来判断的。那么，如果我们能把我们的驱动程序信息中的Rank值修改到&#8220;可信任&#8221;空间， <br>那么系统是否就会信任我们的驱动程序，而自动对它进行安装呢？答案是，有可能。我不敢说肯定可以，原因 <br>后面会提到。但是，如何修改驱动程序信息的Rank值呢？这就要用到&#8220;协作安装程序&#8221;。 <br><br>我们知道，在设备的安装过程中，Setup要向设备类安装程序、类协作安装程序和设备协作安装程序发送 <br>&#8220;设备安装功能码&#8221;（如果有这些安装程序的话）。ddk文档中又说，类安装程序和类协作安装程序可以对 <br>DIF_SELECTBESTCOMPATDRV请求进行处理（设备协作安装程序不可以）。在对DIF_SELECTBESTCOMPATDRV进行处理 <br>的时候，类安装程序和类协作安装程序可以修改驱动程序列表中各驱动程序的信息。答案越来越清晰了，我们 <br>只要写一个类协作安装程序，对DIF_SELECTBESTCOMPATDRV进行处理，修改我们想要安装的驱动程序的Rank值， <br>那么就可能骗过系统，使系统相信我们的驱动程序，并完成自动安装。关于编写协作安装程序的具体要求和方法， <br>可以参考ddk文档中的&#8220;Writing a Co-installer（编写协作安装程序）&#8221;和ddk\src\general\toaster\coinstaller。 <br><br>接下来，我们来了解一下，在类协作安装程序处理DIF_SELECTBESTCOMPATDRV时，应该做哪些事情。 <br>（1）首先，调用SetupDiEnumDriverInfo遍历驱动程序列表，获得每个驱动程序的信息――一个 <br>SP_DRVINFO_DATA结构。 <br>（2）接着，用（1）中获得的SP_DRVINFO_DATA作为输入参数，调用SetupDiGetDriverInstallParams， <br>获得驱动程序安装参数――一个SP_DRVINSTALL_PARAMS结构，其中我们想要修改的Rank赫然在列。你可以按 <br>照自己的需要修改Rank的值，在这儿我们肯定是要把它改为0了（0表示驱动程序与设备最匹配）。 <br>（3）最后，把修改后的SP_DRVINSTALL_PARAMS结构作为输入，调用SetupDiSetDriverInstallParams将我们修改 <br>的值设置生效。 <br>在类协作安装程序中只需作如此处理，便可以使Setup此后信任我们的驱动程序，从而达到我们想瞒天过海的目的。 <br><br>再稍微提一下类协作安装程序的注册。协作安装程序做好了，如何使它参与到设备安装的过程中来呢？我们 <br>必须注册它。ddk文档对此讲得非常清楚了，参看&#8220;Registering a Class Co-installer&#8221;，我就不在这儿把它翻译出来了。 <br><br>最后，要提醒一点：必须为我们的usb设备定义一个新的设备setup类，然后将我们的协作安装程序注册为这个 <br>setup类的类协作安装程序。如果我们让设备仍然属于usb setup类，并将我们的类协作安装程序注册为usb <br>setup类的一个协作安装程序，那么在安装过程中，Setup仍然弹出一些窗体影响我们设备的自动安装，似乎我们的小聪明 <br>并没能瞒过它。这就是前面我说修改Rank值为&#8220;可信任&#8221;只是有可能瞒过系统而不是肯定能够瞒过系统的原因。为什么会出现 <br>这种情况呢？从现象看，我感觉是usb setup类的类安装程序仍然发现我们的驱动程序是不可信任的。但是，Setup是以类协作 <br>安装程序、设备协作安装程序和类安装程序的顺序调用它们的，在Setup调用usb setup类安装程序之前，我们已经修改了驱动程序的 <br>Rank值。按理说，它应该不会发现驱动程序是不可信任的。这是一个问题，具体原因我还没有弄明白，希望有知其所以然者，能给 <br>点提示！不管如何，通过实验我发现，只要我们定义了新的setup类，那么我们就可以骗过系统Setup组件，使其自动为我们的设备 <br>安装驱动程序。 <br><br>就写这些，有兴趣的朋友可以试一下！我不想把具体的实现过程一步一步地写出来，更不愿提供具体的实现代码。 <br>因为我认为只要把原理和方法讲清楚了（但愿我讲得还算清楚），每个人都可以在此基础上做自己的事情。 <br><br>不管各位朋友看完之后感觉如何，能夸就夸夸，该骂就骂骂，都顶一下！<br><img src ="http://www.cppblog.com/momoxiao/aggbug/107330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:05 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>coinstaller--DDK文档翻译zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107329.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107329.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107329.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107329.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107329.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107329.html</trackback:ping><description><![CDATA[<div class="f14" id="read_tpc">编写协同安装程序<br>协同安装程序是微软公司开发的win32的DLL，它是用来帮助在Windows 2000系统上进行设备安装。它被Setup API调用作为类安装程序的&#8220;助手&#8221;。例如，供应商可以提供协同安装程序将特定设备信息写入INF文件无法处理的注册表中。<br><br>本章内容：<br>l 4.1 协同安装程序总览<br>l 4.2 协同安装程序界面<br>l 4.3 协同安装程序操作<br>l 4.4 注册协同安装程序<br>1.1 协同安装程序总览<br>由Setup API调用的协同安装程序如图4-1所示。<br>图4-1 协同安装程序在设备安装中的分工<br>带有阴影的方框表示可由IHV和OEM提供的组件，其他组件则由OS提供。参见第1章&#8220;设备安装总览&#8221;可以了解更多的有关安装组件的信息。<br>协同安装程序可以是设备专用或类专用的。Setup API只在安装协同安装程序为其注册的设备时才调用一个设备专用的协同安装程序。操作系统(OS)及供应商可以为一个设备注册零个或多个设备专用的协同安装程序。在为协同安装程序注册安装设备设置类的任何设备时，Setup API调用类协同安装程序。操作系统及供应商可以为一个设备设置类注册一个或多个类协同安装程序。除此之外，类协同安装程序还可以为一个或多个设置类注册。<br><br>GUI模式设置、新设备DLL以及定制设置应用程序通过调用带有设备安装函数代码(DIF代码)的SetupDiCallClassInstaller来安装设备。对于每一个DIF请求，SetupDiCallClassInstaller调用为设备设置类注册的任何类协同安装程序，调用为特定设备注册的任何设备协同安装程序，以及由系统提供用于设备设置类的类安装程序(如果有的话)。<br><br>定制设置应用程序须调用SetupDiCallClassInstaller而不是直接调用协同安装程序或类安装程序。这个函数可以保证所有注册的协同安装程序都能被正确调用。<br><br>类协同安装程序一般都在设备安装之前注册，而设备专用的协同安装程序则是作为设备安装的一部分被注册的。因此类协同安装程序总是在第一次构建时就被添加到协同安装程序列表之中，并在设备安装时被所有DIF请求调用。特定设备协同安装程序则是在为该设备完成DIF_REGISTER_COINSTALLERS请求之后被添加到重安装列表之中的(或是在调用了SetupDiRegisterCoDeviceInstallers之后)。特定设备协同安装程序并不参与以下DIF请求：DIF_ALLOWINSTALL、DIF_INSTALLDEVICEFILES及DIF_SELECTBESTCOMPATDRV。<br><br>如果协同安装程序需要响应以下任何一个DIF请求，它就必须是一个类协同安装程序(而不是设备专用协同安装程序)：<br>l DIF_FIRSTTIMESETUP，DIF_DETECT*<br>l DIF_NEWDEVICEWIZARD_PRESELECT<br>l DIF_NEWDEVICEWIZARD_SELECT<br>l DIF_NEWDEVICEWIZARD_PREANALYZE<br>l DIF_NEWDEVICEWIZARD_POSTANALYZE<br><br>设备协同安装程序并不适用于这样的上下文，这是因为并没有标识出某个特定的设备，或是因为在安装的这个初始阶段还没有注册过设备安装程序。<br>图4-2显示了在注册了任意一个特定设备的协同安装程序之后，SetupDiCallClassInstaller调用协同安装程序及类安装程序的顺序。<br><br>图4-2 为DIF请求调用协同安装程序的处理及后处理示例<br>在图4-2所演示的示例中，为该设备的设置类注册了两个类协同安装程序以及一个特定设备协同安装程序。以下步骤对应于图4-2中的带圆圈的数字标号：<br><br>1. SetupDiCallClassInstaller调用第一个类协同安装程序，同时指定一个表示安装请求正在处理中的DIF代码(在本例中是DIF_INSTALLDEVICE)。协同安装程序在安装请求中有参与的选择权。本例中，第一个注册的类协同安装程序返回NO_ERROR。<br>2. 接下来，SetupDiCallClassInstaller调用任意额外注册的类协同安装程序。在本例中，第二个类安装程序返回了ERROR_DI_POSTPROCESSING_REQUIRED，它要求在后处理之后再调用协同安装程序。<br>3. SetupDiCallClassInstaller调用任意注册的设备专用协同安装程序。<br>4. 在调用了所有的注册过的协同安装程序后，如果设备的设置类有一个系统提供的类安装程序，SetupDiCallClassInstaller就调用它。在本例中，类安装程序返回ERROR_DI_DO_DEFAULT，这是类安装程序的一个典型返回值。<br>5. 如果有一个缺省的设备处理驱动程序，SetupDiCallClassInstaller就为安装请求调用它。DIF_INSTALLDEVICE有一个缺省的设备处理驱动程序SetupDiInstallDevice，它是Setup API的一部分。<br>6. SetupDiCallClassInstaller调用任何要求后处理的协同安装程序。在本例中，第二个类协同安装程序要求了后处理。<br>除了协同安装程序在它的单个入口点被再一次调用外，协同安装程序的后处理与驱动程序的IoCompletion例程相似。当SetupDiCallClassInstaller为后处理调用协同安装程序时，它将PostProcessing设为TRUE，并将InstallResult设为Context参数中的恰当值。在本例中，Context.InstallResult是NO_ERROR，这是因为成功地执行了缺省的设备处理驱动程序。<br>在后处理中，SetupDicallClassInstaller反向调用了协同安装程序。如果图4-2中的所有协同安装程序都已返回了ERROR_DI_POSTPROCESSING_REQUIRED，那么SetupDiCallClassInstaller就会为后处理先调用Device_Coinstaller_l，之后再是Class_Coinstaller_2，和Class_Coinstaller_1。类安装程序并不要求后处理，只有协同安装程序才要求。<br>即使先前的协同安装程序在安装请求中失败，要求后处理的协同安装程序也会被调用。<br>1.2 安装程序界面<br>协同安装程序具有以下原型：<br>typedef<br>DWORD<br>( CALLBACK* COINSTALLER_PROC) (<br>IN DI_FUNCTION InstallFunction,<br>IN HDEVINFO DeviceInfoSet,<br>IN PSP_DEVINFO_DADA DeviceInfoData OPTIONAL,<br>IN OUT PCOINSTALLER_CONTEXT_DATA Context<br>);<br>InstallFunction指定了正被处理的设备安装请求，在其中协同安装程序具有参与的选择权。例如，DIF_INSTALLDEVICE。参见《Windows 2000 Driver Development Reference》一书的第一卷第3部分的第5章&#8220;安装功能代码&#8221;有关&#8220;在DIF代码上的文档处理&#8221;内容。<br>DeviceInfoSet提供了一个设备信息集的标识值。<br>DeviceInfoData有选择性地标识作为设备安装请求的目标设备。如果这个参数是非NULL的，它就在设备信息集中标识一个元素。当SetupDiCallClassInstaller调用一个特定设备协同安装程序时，DeviceInfoData为非NULL。特定类协同安装程序可以同一个具有NULL DeviceInfoData的DIF请求（如DIF_DETECT或DIF_FIRSTTIMESETUP）一起被调用。<br>Context指向该安装请求的特定协同安装程序上下文结构。这个上下文信息的格式如下：<br>Typedef struct<br>_COINSTALLER_CONTEXT_DATA {<br>BOOLEAN PostProcessing;<br>DWORD InstallResult;<br>PVOID PrivateData;<br>} COINSTALLER_CONTEXT_DATA, *PCOINSTALLER_CONTEXT_DATA;<br><br>当在恰当的类安装程序（如有的话）处理了InstallFunction之后再调用协同安装程序时，PostProcessing为TRUE。PostProcessing对协同安装程序是只读的。<br>如果PostProcessing为FALSE，则InstallResult不相关。如果PostProcessing为TRUE，InstallResult就是安装请求的当前状态。该值为NO_ERROR或是一个由为该安装请求调用的先前部分返回的错误状态。协同安装程序可以为它的函数返回通过返回该值传送状态，或者可以返回其他状态。InstallResult对协同安装程序是只读的。<br>PrivateData指向一个被分配的协同安装程序缓冲。如果协同安装程序设置该指针并要求后处理，那么当SetupDiCallClassInstaller为后处理调用协同安装程序时，将该指针传给这个协同安装程序。<br>设备协同安装程序返回以下一个值：<br>l NO_ERROR<br>协同安装程序对特定的InstallFunction执行恰当的动作，或协同安装程序决定它无需为该请求执行任何操作。<br>l ERROR_DI_POSTPROCESSING_REQUIRED<br>协同安装程序对特定的InstallFunction执行任何恰当的操作，同时在类安装已处理了该请求之后并要求被再次调用。<br>l A Win32 error<br>协同安装程序遇到一个错误。<br>协同安装程序不会设置ERROR_DI_DO_DEFAULT的返回状态。这个状态只能由类安装程序使用。如果一个协同安装程序返回了这样的状态，那么SetupDiCallClassInstaller将不能正确地处理DIF_Xxx请求。协同安装程序也可能在后处理传送中传输ERROR_DE_DO_DEFAULT的一个返回状态，但是它永远不会设置这个值。<br>1.3 协同安装程序操作<br>协同安装程序是用户模式的Win32 DLL，它为注册编写额外的配置信息或执行要求动态信息的其他安装任务，而该动态信息无法通过编写INF来得到。<br>协同安装程序可以完成以下一些或所有的任务：<br>l 打开InstallFunction来处理仅一个或少量的DIF_Xxx请求。<br>l 根据它是否被后处理调用来执行不同的操作（也就是Contex-&gt;PostProcessing是否为TRUE?）<br>l 当为后处理调用时，检查Context-&gt;InstallResult。如果它不是NO_ERROR，就进行任何必需的清除并返回InstallResult。<br>协同安装程序必须不能给最终用户显示任何的UI。协同安装程序应该为设备提供恰当的缺省值。如果它没有缺省值并要求用户输入，那么其他的设备支持组件就应提示用户稍后的所需输入。例如，若调制解调器没有正确的拨号属性设置，则需在用户使用调制解调器而不是在设备设置时提示他们。<br>1.3.1 处理DIF代码<br>每个DIF代码的参考页都继续了以下一些或全部的部分：<br>何时发送<br>描述Setup应用程序发送该DIF请求的典型时间及原因。<br>由谁处理<br>指出允许哪些安装程序处理该请求。该安装程序包括了类安装程序、类协同安装程序（设置-类范围的协同安装程序），以及设备协同安装程序（特定设备协同安装程序）。<br>输入<br>SetupDiCallClassInstaller通过在它的主入口点调用安装程序给一个安装程序发送一个DIF请求。除了DIF代码之外，这个功能提供与某请求相关的额外信息。参见每个DIF代码的参考页可得到与每个请求一起提供的信息细节。以下列表包括了额外输入的一般描述，还列出了用于处理参数的SetupDiXxx函数：<br>l DeviceInfoSet<br>为设备信息集提供一个标识值。<br>该标识值是不透明的。利用这个标识值，例如，在调用中将设备信息集标识到SetupDiXxx函数。<br>DeviceInfoSet可能具有相联的设备设置类。如果是这样的，则调用SetupDiGetDeviceInfoListClass以得到类GUID。<br>l DeviceInfoData<br>有选择性地给一个SP_DEVINFO_DATA结构提供一个指针，该结构在设备信息集中标识了一个设备。<br>l Device Installation Parameters<br>这些非直接的参数为SP_DEVINSTALL_PARAMS结构中的设备安装提供了信息。如果DeviceInfoData是非NULL，就有与DeviceInfoData相关的设备安装参数。如果DeviceInfoData为NULL，则设备安装参数就与DeviceInfoSet相关的设备安装参数。<br>调用SetupDiGetDeviceInstallParams以得到设备安装参数。<br>l Class Installation Parameters<br>将可选的非直接参数指定给某个DIF请求。它们尤其是&#8220;DIF请求参数&#8221;。例如，一个DIF_REMOVE安装请求的类安装参数被包含在一个SP_REMOVEDEVICE_PARAMS结构中。<br>每个SP_XXX_PARAMS结构开始于一个固定大小的SP_CLASSINSTALL-HEADER。<br>调用SetupDiGetClassInstallParams以得到类安装参数。<br>如果DIF请求具有类安装参数，就有与DeviceInfoSet相关的参数集，及与DeviceInfoData相关的另一个参数集（如果DIF请求指定了DeviceInfoData）。SetupDiGetClassInstallParams返回了可得到的最特定参数。<br>l 上下文 （Context）<br>协同安装程序具有一个可选的上下文参数。<br>l 输出 （Output）<br>描述这个DIF代码所需的输出。<br>如果安装程序修改了设备安装参数，那么在返回之前安装程序必须调用SetupDiSetDeviceInstallParams来应用改变。类似地，如果安装程序修改DIF代码的类安装参数，安装程序必须调用SetupDiSetClassInstallParams。<br>l 返回值 (Return Value)<br>指定DIF代码的恰当返回值。参见图4-3中有关返回值的更多信息。<br>l 缺省处理程序 (Default Handler)<br>指定SetupDi函数，它执行DIF代码的系统定义操作。并非所有的DIF代码都具有缺省处理程序。除非协同安装程序或类安装程序采取步骤阻碍调用缺省处理程序，SetupDiCallClassInstaller才会在它调用类安装程序之后再调用DIF代码的缺省处理程序（但却是在它调用任何为后处理注册的协同安装程序之前）。<br>操作 (Operation)<br>描述安装程序可能用来处理DIF请求的典型任务。<br>其他 (See Also)<br>相关信息源的列表。<br>图4-3中是SetupDiCallClassInstaller中处理DIF代码的事件序列。<br>操作系统执行每个DIF代码的一些操作。由供应商提供的协同安装程序及类安装程序可以参与安装行为。请注意即使DIF代码失败了，SetupDiCallClassInstaller也调用了为后处理注册的协同安装程序。<br>1.4 注册协同安装程序<br>协同安装程序可以为某个设置类的单个或全部设备注册。当特定设备中的一个已被安装时，这些设备的协同安装程序就通过INF文件动态注册。类协同安装程序被手工注册或由定制的设置应用程序及一个INF注册。<br>如要了解更多的信息，可参见《Registering a Device-Specific Coinstaller》及《Registering a Class Coinstaller》。<br>如要更新协同安装程序，DLL的每个新版本都需有一个新的文件名，这是因为当用户在设备属性页上点击Update Driver按纽时，尤其要用到DLL。<br>图4-3 在SetupDiCallClassInstaller中的DIF代码处理流程图<br>1.4.1 注册设备专用的协同安装程序<br>为了注册设备专用的协同安装程序，将以下部分添加到设备的INF文件中：<br>； ：<br>； ：<br>[DestinationDirs]<br>XxxCopyFilesSection = 11 \\DIRID_SYSTEM<br>\\ Xxx = driver or dev . prefix<br>； ：<br>； ：<br>[XxxInstall . OS-platporm.CoInstallers] \\ OS-platform is optional<br>CopyFiles = XxxCopyFilesSection<br>AddReg = Xxx.OS-platform. CoInstallers_AddReg<br>[XxxCopyFilesSection]<br>XxxCoInstall.dll<br>{Xxx. OS-platform.CoInstallers_AddReg}<br>HKR,,CoInstallers32.0x00010000.&#8221;XxxCoInstall.dll. \<br>XxxCoInstallEntryPoint&#8221;<br>DestinationDirs部分中的项说明XxxCopyFiles部分中列出的文件将被复制到系统目录下。Xxx前缀标识出驱动程序、设备或设备组（如cdrom_CopyFilesSection）。Xxx前缀应是唯一的。<br>协同安装程序安装节的名称可以用可选的操作系统/架构扩展（如cdrom_install.NTx86.CoInstallers）来修饰。<br>Xxx_AddReg部分中的项在设备驱动程序密钥中建立一个CoInstallers32值项。该项包含了协同安装程序DLL，而且可选地还可有一个特定入口点。如果忽略这个输入点，则缺省为CoDeviceInstall。十六进制标志参数（0x00010000）指明这是REG_MULTI_SZ值项。<br>为了给设备注册多于一个的特定设备协同安装程序，复制每个协同安装程序的文件并在注册项中包含至少一个信息串。例如，为了注册两个协同安装程序，建立如下部分：<br>； ：<br>； ：<br>[DestinationDirs]<br>XxxCopyFilesSection = 11 \\DIRID_SYSTEM<br>\\ Xxx = driver or dev . prefix<br>； ：<br>； ：<br>[XxxInstall . OS-platporm.CoInstallers] \\ OS-platform is optional<br>CopyFiles = XxxCopyFilesSection<br>AddReg = Xxx.OS-platform. CoInstallers_AddReg<br>[XxxCopyFilesSection]<br>XxxCoInstall.dll \\ copy 1st coinst. file<br>YyyCoinstall.dll \\ copy 2nd coinst. file<br>[Xxx. OS-platform.CoInstallers_AddReg]<br>HKR..CoInstallers32.0x00010000. \<br>&#8220;XxxCoInstall.dll. XxxCoInstallEntryPoint&#8221;. \<br>&#8220;YyyCoInstall.dll. YyyCoInstallEntryPoint&#8221;<br>\\ add both to registry<br>当执行设备专用的协同安装程序INF部分时，该协同安装程序是在安装一个设备的过程中被注册的。接着Setup API在安装过程中的每个随后步骤上调用协同安装程序。如果为一个设备注册多个协同安装程序，那么Setup API按其在注册中所列顺序调用它们。<br>1.4.2 注册类协同安装程序<br>如要为某个设置类的每个设备都注册一个协同安装程序，可按以下所列建立一个注册表项<br>HKLM\System\CurrentControlSet\Control\CoDeviceInstallers subkey:<br>{setup-class-GUID}: REG_MULTI_SZ : &#8220;XyzCoInstall.dll. XyzCoInstallEntryPoint\0\0&#8221;<br>该系统建立了CoDeviceInstallers密钥。Setup-class-GUID为设备设置类指定GUID。如果协同安装程序提供设备的多个类，它就建立每个设置类的单个值项。<br>我们不能覆盖先前写给setup-class-GUID密钥的其他协同安装程序。读取这个密钥，将自己的协同安装程序信息串附加到REG_MULTI_SZ列表中，并将该密钥写回到注册表中。<br>如果忽略CoInstallEntryPoint，则缺省为CoDeviceInstall。<br>协同安装程序DLL必须也被复制到系统目录下。<br>一旦复制了文件且做出了注册表项，类协同安装程序就可被用来调用相关设备和服务。<br>不用手工建立注册项来注册一个类协同安装程序，就可以利用INF文件注册它，如下所示。<br>[version]<br>signature = &#8220;$Windows NT$&#8221;<br>[DestinationDirs]<br>DefaultDestDir = 11 / / DIRID_SYSTEM<br>[DefaultInstall]<br>CopyFiles = @classXcoinst.dll<br>AddReg = CoInstaller_AddReg<br>[CoInstaller_AddReg]<br>HKLM.System\CurrentControlSet\Control\CoDeviceInstallers, \<br>{setup-class-GUID}, 0x00010008, &#8220;classXcoinst.dll,classXCoInstaller&#8217;<br>; above line uses the line continuation character (\)<br>这个例子INF将文件classXcoinst.dll复制到系统目录下并在CoDeviceInstallers密钥下建立了一个setup-class-GUID类的项。Xxx-AddReg部分的项指示两个标志：&#8221;00010000&#8221;标志表示这个项是REG_MULTI_SZ，而&#8221;00000008&#8221;标志表示新值将被附加到任何已有的值上（如果新值并未存在于信息串中）。<br>这样一个注册表类协同安装程序的INF可由右点击安装或通过SetupInstallFromInfSection应用程序激活。</div>
<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #000000;">贴段伪代码<br>HRESULT<br>CoInstaller(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;&nbsp;&nbsp;DI_FUNCTION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InstallFunction,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;&nbsp;&nbsp;HDEVINFO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DeviceInfoSet,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;&nbsp;&nbsp;PSP_DEVINFO_DATA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DeviceInfoData,&nbsp;OPTIONAL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;OUT&nbsp;PCOINSTALLER_CONTEXT_DATA&nbsp;Context<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br>{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">switch</span><span style="color: #000000;">(InstallFunction)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;DIF_SELECTBESTCOMPATDRV:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #000000;">Context</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">PostProcessing)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgOut(</span><span style="color: #000000;">"</span><span style="color: #000000;">DIF_SELECTBESTCOMPATDRV</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ERROR_DI_POSTPROCESSING_REQUIRED;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">post&nbsp;processing</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgOut(</span><span style="color: #000000;">"</span><span style="color: #000000;">DIF_SELECTBESTCOMPATDRV&nbsp;PostProcessing</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">We&nbsp;will&nbsp;do&nbsp;something&nbsp;here</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SP_DRVINFO_DATA&nbsp;DriverInfoData;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SP_DRVINSTALL_PARAMS&nbsp;DriverInstallParams;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DriverInfoData.cbSize&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(SP_DRVINFO_DATA);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DriverInstallParams.cbSize&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(SP_DRVINSTALL_PARAMS);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(SetupDiEnumDriverInfo(DeviceInfoSet,DeviceInfoData,SPDIT_CLASSDRIVER&nbsp;,</span><span style="color: #000000;">0</span><span style="color: #000000;">,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">DriverInfoData))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(SetupDiGetDriverInstallParams(DeviceInfoSet,DeviceInfoData,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">DriverInfoData,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">DriverInstallParams))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(DriverInstallParams.Rank&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DriverInstallParams.Rank&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #000000;">SetupDiGetDriverInstallParams(DeviceInfoSet,DeviceInfoData,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">DriverInfoData,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">DriverInstallParams))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgOut(</span><span style="color: #000000;">"</span><span style="color: #000000;">SetupDiGetDriverInstallParams</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;DIF_REMOVE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgOut(</span><span style="color: #000000;">"</span><span style="color: #000000;">DIF_REMOVE</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">default</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;NO_ERROR;<br>}</span></div><img src ="http://www.cppblog.com/momoxiao/aggbug/107329.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:05 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107329.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于WIN2K下的驱动，不能重复安装的问题。zz</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/06/107328.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 16:02:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/06/107328.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107328.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/06/107328.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107328.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107328.html</trackback:ping><description><![CDATA[<div class="f14" id="read_tpc">原在98下用DRIVERSTUDIO写的一个WMD模式的PCI卡驱动，现在2K环境下重新编译并修改INF文件后，顺利<u><font color="red">安装</font></u>并能正常工作。<br>由于今天对驱动的部分功能作了调整，于是将驱动卸载后准备重新<u><font color="red">安装</font></u>调整过的程序，结果刷新硬件后，系统又自己找到了老的驱动，强行指定新的驱动的位置后，<u><font color="red">安装</font></u>到一半，系统蓝屏并重新启动。并且，启动到一半时，又蓝屏报警说硬件有故障并且停止在报警位置。<br>重新冷启动并按F8键，使用前一次正确的启动配置文件，系统启动后，仍使用旧的驱动程序。<br><br>此过程试了好几遍，并且，新<u><font color="red">安装</font></u>的驱动程序包括INF文件就是使用和原来一样的程序，情况还是一样，好象2K不允许<u><font color="red">重复</font></u><u><font color="red">安装</font></u>驱动一样！现在，要调整程序，只好将.SYS文件COPY到SYSTEM32文件夹下再重新启动计算机，<br><br>不知道有没有朋友遇到过这种情况，如何解决。</div>
-----------------------------------------------<br><br>
<div class="f14" id="read_591624">我遇到过，后来我做了个批处理，每次修改好程序编译完以后，就执行这个批处理，它便帮我将原来的.sys文件和.inf文件全部删除掉了。</div>
--------------------------------------------------<br>蓝屏死机有可能是驱动有问题，<br><br>驱动卸载后，有时不会将<u><font color="red">安装</font></u>后拷贝导系统目录的文件全部删除，<br>有时要手动删除，如inf文件，<br>如果你inf文件改变了，就要到winnt\\inf目录找到以前的把它删掉<img src ="http://www.cppblog.com/momoxiao/aggbug/107328.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-06 00:02 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/06/107328.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(zz)初步实现系统级拦截应用程序取硬盘物理序列号 </title><link>http://www.cppblog.com/momoxiao/archive/2010/02/05/107325.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 15:57:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/05/107325.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107325.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/05/107325.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107325.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107325.html</trackback:ping><description><![CDATA[<font color="#333333">标 题:</font><font color="#000000"> 【原创】初步实现系统级拦截应用程序取硬盘物理序列号</font><font color="#666666"><br><font color="#333333">作 者:</font> <font color="#000000">rockhard</font><br><font color="#333333">时 间:</font> 2006-11-29,12:09<br><font color="#333333">链 接:</font> http://bbs.pediy.com/showthread.php?t=35626<br></font><br>【文章标题】:&nbsp;初步实现系统级拦截应用程序取硬盘物理序列号<br>【文章作者】:&nbsp;rockhard<br>【作者邮箱】:&nbsp;wnh1@sohu.com<br>【作者声明】:&nbsp;只是感兴趣，没有其他目的。失误之处敬请诸位大侠赐教!<br>--------------------------------------------------------------------------------<br>【详细过程】<br>&nbsp;&nbsp;以前想模拟某个程序取硬盘系列号，就将一个DLL注入进去，拦截DeviceIoControl的返回值，将其修改为目标硬盘的值。<br>&nbsp;&nbsp;后来看到REGMON&nbsp;从SSDT着手拦截注册表操作，可以看到任何程序的读写操作，就仿着改了一下程序。经测试可以欺骗相当<br>&nbsp;&nbsp;一部分程序读硬盘序列号，包括ASPROTECT及用其加密算法的子孙:)。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;我的思路是这样的：<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1、首先用程序取自己的真正的硬盘序列号，假设为XXXX<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;2、拦截系统的ZwDeviceIoControlFile，并判断入口参数中的IoControlCode&nbsp;，只有某几个特定的值用来取序列号的，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;目前在所有的程序中取硬盘序列号的，我只发现两个值,一个是0x7c088，另外一个是什么忘了。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果IoControlCode为上面的值，读取系统原有的ZwDeviceIoControlFile返回BUFFER，并用串匹配方法查找这个返回值中存在<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不存在XXXX，如果存在，替换为你要欺骗的值.<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;代码很简单：<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;UCHAR&nbsp;__DiskSerial[DISK_SERIAL_BUFF_LENGTH]={0};<br>&nbsp;&nbsp;UCHAR&nbsp;__ChangeTo&nbsp;&nbsp;[DISK_SERIAL_BUFF_LENGTH]={0};<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//一个简单的低率串匹配算法&nbsp;，判断一个串S1是不是另外一个串S2的子串<br>&nbsp;&nbsp;PUCHAR&nbsp;IsSubString(PUCHAR&nbsp;String,&nbsp;PUCHAR&nbsp;SubString&nbsp;,ULONG&nbsp;StringLength&nbsp;,ULONG&nbsp;SubStringLength)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;i,j;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i&lt;StringLength&nbsp;-&nbsp;SubStringLength&nbsp;+1&nbsp;;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(j=0;j&lt;SubStringLength;j++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(String[i+j]!=SubString[j])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(j==SubStringLength)&nbsp;&nbsp;//match&nbsp;a&nbsp;substring<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;String+i;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//----------------------------------------------------------------------<br>&nbsp;&nbsp;//<br>&nbsp;&nbsp;//&nbsp;&nbsp;Our&nbsp;own&nbsp;routine&nbsp;for&nbsp;ZwDeviceIocontrolFile<br>&nbsp;&nbsp;//&nbsp;&nbsp;We&nbsp;change&nbsp;the&nbsp;hard&nbsp;disk&nbsp;serial&nbsp;number&nbsp;value&nbsp;requested&nbsp;by&nbsp;user<br>&nbsp;&nbsp;//<br>&nbsp;&nbsp;//----------------------------------------------------------------------<br>&nbsp;&nbsp;NTSTATUS&nbsp;HookZwDeviceIoControlFile(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;HANDLE&nbsp;FileHandle,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;HANDLE&nbsp;Event&nbsp;OPTIONAL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PIO_APC_ROUTINE&nbsp;ApcRoutine&nbsp;OPTIONAL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PVOID&nbsp;ApcContext&nbsp;OPTIONAL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUT&nbsp;PIO_STATUS_BLOCK&nbsp;IoStatusBlock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;ULONG&nbsp;IoControlCode,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PVOID&nbsp;InputBuffer&nbsp;OPTIONAL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;ULONG&nbsp;InputBufferLength,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUT&nbsp;PVOID&nbsp;OutputBuffer&nbsp;OPTIONAL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;ULONG&nbsp;OutputBufferLength<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;rc;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rc&nbsp;=&nbsp;RealZwDeviceIoControlFile&nbsp;(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileHandle,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Event,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ApcRoutine,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ApcContext,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatusBlock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoControlCode,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InputBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InputBufferLength,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputBufferLength<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//判断IoControlcode是不是取序列号的值<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if((0x7c088&nbsp;==IoControlCode)&nbsp;&amp;&amp;&nbsp;OutputBufferLength&nbsp;&gt;DISK_SERIAL_BUFF_LENGTH){<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//判断返回值中是否包含当前的硬盘序列号，是的话用假的替换<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PUCHAR&nbsp;Locate&nbsp;=&nbsp;IsSubString(OutputBuffer,__DiskSerial,OutputBufferLength,DISK_SERIAL_BUFF_LENGTH);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Locate){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UCHAR&nbsp;i;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i&lt;20;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Locate[i]=&nbsp;__ChangeTo[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(rc);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;目前，驱动只处理了简单的几个应用层的消息，包括停止欺骗，开始欺骗，设置新的欺骗值。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;BOOLEAN&nbsp;&nbsp;HDHookDeviceControl(&nbsp;IN&nbsp;PFILE_OBJECT&nbsp;FileObject,&nbsp;IN&nbsp;BOOLEAN&nbsp;Wait,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PVOID&nbsp;InputBuffer,&nbsp;IN&nbsp;ULONG&nbsp;InputBufferLength,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUT&nbsp;PVOID&nbsp;OutputBuffer,&nbsp;IN&nbsp;ULONG&nbsp;OutputBufferLength,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;ULONG&nbsp;IoControlCode,&nbsp;OUT&nbsp;PIO_STATUS_BLOCK&nbsp;IoStatus,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IN&nbsp;PDEVICE_OBJECT&nbsp;DeviceObject&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOLEAN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retval&nbsp;=&nbsp;FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;i;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Its&nbsp;a&nbsp;message&nbsp;from&nbsp;our&nbsp;GUI!<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;STATUS_SUCCESS;&nbsp;//&nbsp;Assume&nbsp;success<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Information&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Assume&nbsp;nothing&nbsp;returned<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(&nbsp;IoControlCode&nbsp;)&nbsp;{<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;开始欺骗<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;HDHOOK_HOOK:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HookStart();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;停止欺骗<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;HDHOOK_UNHOOK:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HookStop();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;告诉驱动当前自己硬盘的序列号值为多少<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;HDHOOK_SETSELFVALUE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;InputBufferLength&nbsp;&lt;&nbsp;DISK_SERIAL_BUFF_LENGTH&nbsp;||&nbsp;InputBuffer&nbsp;==&nbsp;NULL){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Status&nbsp;=&nbsp;STATUS_INVALID_PARAMETER;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;&nbsp;i&lt;&nbsp;DISK_SERIAL_BUFF_LENGTH&nbsp;;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__DiskSerial[i]&nbsp;=&nbsp;((UCHAR&nbsp;*)InputBuffer)[i];<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设置新的欺骗的硬盘序列号<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;HDHOOK_SETEMULABLEVALUE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;InputBufferLength&nbsp;&lt;&nbsp;DISK_SERIAL_BUFF_LENGTH&nbsp;||&nbsp;InputBuffer&nbsp;==&nbsp;NULL){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Status&nbsp;=&nbsp;STATUS_INVALID_PARAMETER;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0;i&lt;&nbsp;DISK_SERIAL_BUFF_LENGTH&nbsp;;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__ChangeTo[i]&nbsp;=&nbsp;((UCHAR&nbsp;*)InputBuffer)[i];<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;//返回驱动的版本号<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;HDHOOK_VERSION:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;OutputBufferLength&nbsp;&lt;&nbsp;sizeof(ULONG)&nbsp;||<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputBuffer&nbsp;==&nbsp;NULL&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Status&nbsp;=&nbsp;STATUS_INVALID_PARAMETER;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*(ULONG&nbsp;*)OutputBuffer&nbsp;=&nbsp;REGMONVERSION;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Information&nbsp;=&nbsp;sizeof(ULONG);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoStatus-&gt;Status&nbsp;=&nbsp;STATUS_INVALID_DEVICE_REQUEST;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TRUE;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;////////////////////////////////////////////////<br>&nbsp;&nbsp;应用层程序可以通过如下简单代码与驱动进行通信：<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;#define&nbsp;HDHOOK_HOOK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ULONG)&nbsp;CTL_CODE(&nbsp;FILE_DEVICE_REGMON,&nbsp;0x00,&nbsp;METHOD_BUFFERED,&nbsp;FILE_ANY_ACCESS&nbsp;)<br>&nbsp;&nbsp;#define&nbsp;HDHOOK_UNHOOK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ULONG)&nbsp;CTL_CODE(&nbsp;FILE_DEVICE_REGMON,&nbsp;0x01,&nbsp;METHOD_BUFFERED,&nbsp;FILE_ANY_ACCESS&nbsp;)<br>&nbsp;&nbsp;#define&nbsp;HDHOOK_VERSION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ULONG)&nbsp;CTL_CODE(&nbsp;FILE_DEVICE_REGMON,&nbsp;0x02,&nbsp;METHOD_BUFFERED,&nbsp;FILE_ANY_ACCESS&nbsp;)<br>&nbsp;&nbsp;#define&nbsp;HDHOOK_SETSELFVALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ULONG)&nbsp;CTL_CODE(&nbsp;FILE_DEVICE_REGMON,&nbsp;0x03,&nbsp;METHOD_BUFFERED,&nbsp;FILE_ANY_ACCESS&nbsp;)<br>&nbsp;&nbsp;#define&nbsp;HDHOOK_SETEMULABLEVALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ULONG)&nbsp;CTL_CODE(&nbsp;FILE_DEVICE_REGMON,&nbsp;0x04,&nbsp;METHOD_BUFFERED,&nbsp;FILE_ANY_ACCESS&nbsp;)<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;#define&nbsp;DISK_SERIAL_BUFF_LENGTH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;20<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//设置新的序列号模拟值<br>&nbsp;&nbsp;DeviceIoControl(__SysHandle,HDHOOK_SETEMULABLEVALUE,szEmulSerial,DISK_SERIAL_BUFF_LENGTH,&nbsp;NULL,&nbsp;0,&nbsp;&amp;dwDummy,&nbsp;NULL)&nbsp;;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//告诉驱动自己的硬盘序列号<br>&nbsp;&nbsp;DeviceIoControl(__SysHandle,HDHOOK_SETSELFVALUE,szBuffer,DISK_SERIAL_BUFF_LENGTH,&nbsp;NULL,&nbsp;0,&nbsp;&amp;dwDummy,&nbsp;NULL)&nbsp;;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//开始拦截<br>&nbsp;&nbsp;DeviceIoControl(__SysHandle,HDHOOK_HOOK,NULL,0,NULL,0,&amp;dwDummy,NULL)&nbsp;;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//停止拦截<br>&nbsp;&nbsp;DeviceIoControl(__SysHandle,HDHOOK_UNHOOK,NULL,0,NULL,0,&amp;dwDummy,NULL)&nbsp;;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;其中__SysHandle是安装驱动的句柄<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;这篇文章的思路来自regmon(regmon版权申明我保留在文件中)，写出来是方便调试那些有正版注册号且以硬盘序列号生成注册码的程序，方便一下大家。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;附件中包含我写的一个简单的UI，用来与驱动通信。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;如果你觉得有用，希望有人能完成如下功能：<br>&nbsp;&nbsp;1、进程过滤功能，只对特定程序拦截。<br>&nbsp;&nbsp;2、考虑将上面的那个串匹配算法改得高效些，数据结构教材上有现成的：）<br>&nbsp;&nbsp;3、那个返回值中有硬盘厂家，磁道数等信息，完成完全模拟，还有IoControlCode&nbsp;的完善。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;若改好了希望能传一份给我&nbsp;:)<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>--------------------------------------------------------------------------------<br>【版权声明】:&nbsp;本文原创于看雪技术论坛,&nbsp;转载请注明作者并保持文章的完整,&nbsp;谢谢!<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2006年11月29日&nbsp;12:03:24<img src ="http://www.cppblog.com/momoxiao/aggbug/107325.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-05 23:57 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/05/107325.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(zz)更改计算机名称</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/05/107324.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 15:56:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/05/107324.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107324.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/05/107324.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107324.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107324.html</trackback:ping><description><![CDATA[<div class="MainNewsContent" id="content" style="table-layout: fixed;">&nbsp;&nbsp;&nbsp;&nbsp;计算机名称是用户在安装Windows时就必须输入的信息，安装了Windows后，用户仍然可以通过&#8220;系统属性&#8221;对话框进行修改。此外，通过修改注册表也可以达到这个目的。 <br><br>&nbsp;&nbsp;&nbsp;&nbsp;（1）打开注册表编辑器。 <br><br>&nbsp;&nbsp;&nbsp;&nbsp;（2）选择HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\parameters子键。 <br><br>&nbsp;&nbsp;&nbsp;&nbsp;（3）双击右侧窗口中的NV&nbsp;Hostname键值项，将老的计算机名称修改为新的计算机名称。 <br><br>&nbsp;&nbsp;&nbsp;&nbsp;（4）完成后关闭注册表编辑器以保存设置，返回桌面按F5刷新即可。如果再次打开&#8220;系统属性&#8221;对话框的&#8220;计算机名&#8221;选项卡，可以看到显示的计算机名称已经被修改为新的了。 </div><img src ="http://www.cppblog.com/momoxiao/aggbug/107324.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-05 23:56 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/05/107324.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(zz)关于ZwWriteFile的问题</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/05/107320.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 15:50:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/05/107320.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107320.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/05/107320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107320.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107320.html</trackback:ping><description><![CDATA[<a href="http://bbs.driverdevelop.com/read.php?tid-21125.html">http://bbs.driverdevelop.com/read.php?tid-21125.html</a><br>-------------<br>
<div class="f14" id="read_tpc">我在AddDevice里调用ZwWriteFile想写一点东西到一个文件里（只是一个练习），但是失败了，为什么？我从设备管理器里看到错误代码是31，是什么意思？什么地方有相关的资料？</div>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #000000;">相关代码：<br>NTSTATUS&nbsp;AddDevice&nbsp;(IN&nbsp;PDRIVER_OBJECT&nbsp;pDriverObject,IN&nbsp;PDEVICE_OBJECT&nbsp;pPdo)<br>{<br>PDEVICE_OBJECT&nbsp;pFdo;<br>NTSTATUS&nbsp;ntStatus&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoCreateDevice(pDriverObject,<br></span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(DEVICE_EXTENSION),NULL,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pFdo);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(ntStatus))<br>{<br>KdPrint((\</span><span style="color: #000000;">"</span><span style="color: #000000;">IoCreateDevice&nbsp;failed&nbsp;-&nbsp;%X\\n\</span><span style="color: #000000;">"</span><span style="color: #000000;">,ntStatus));<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ntStatus;<br>}<br><br>PDEVICE_EXTENSION&nbsp;pdx&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(PDEVICE_EXTENSION)pFdo</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">DeviceExtension;<br>pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">pDriverObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pDriverObject;<br>pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">pFdo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pFdo;<br>pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">pPdo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pPdo;<br><br>UNICODE_STRING&nbsp;unName;<br>RtlInitUnicodeString(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">unName,L\</span><span style="color: #000000;">"</span><span style="color: #000000;">\\\\??\\\\D:\\\\Stone\\\\LogFile.txt\</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>OBJECT_ATTRIBUTES&nbsp;ObjectrAttributes;<br>InitializeObjectAttributes(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">ObjectrAttributes,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">unName,OBJ_OPENIF,NULL,NULL);<br><br>IO_STATUS_BLOCK&nbsp;ioStatusBlock;<br>ntStatus&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;<br>ZwCreateFile(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">hLogFileHandle,FILE_WRITE_DATA&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;FILE_READ_DATA&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;FILE_APPEND_DATA,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">ObjectrAttributes,<br></span><span style="color: #000000;">&amp;</span><span style="color: #000000;">ioStatusBlock,NULL,FILE_ATTRIBUTE_NORMAL,</span><span style="color: #000000;">0</span><span style="color: #000000;">,FILE_OPEN_IF,FILE_RANDOM_ACCESS,NULL,</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(ntStatus))<br>{<br>KdPrint((\</span><span style="color: #000000;">"</span><span style="color: #000000;">ZwCreateFile&nbsp;fialed&nbsp;-&nbsp;%X\\n\</span><span style="color: #000000;">"</span><span style="color: #000000;">,ntStatus));<br>IoDeleteDevice(pFdo);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ntStatus;<br>}<br><br>ntStatus&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoRegisterDeviceInterface(pPdo,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">GUID_TEST,NULL,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">unLinkName);<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(ntStatus))<br>{<br>KdPrint((\</span><span style="color: #000000;">"</span><span style="color: #000000;">IoRegisterDeviceInterface&nbsp;failed&nbsp;-&nbsp;%X\\n\</span><span style="color: #000000;">"</span><span style="color: #000000;">,ntStatus));<br>ZwClose(pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">hLogFileHandle);<br>IoDeleteDevice(pFdo);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ntStatus;<br>}<br><br>TCHAR&nbsp;pContent[]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;\</span><span style="color: #000000;">"</span><span style="color: #000000;">AddDevice&nbsp;is&nbsp;called\</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br>ntStatus&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;WriteToLogFile(pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">hLogFileHandle,pContent,strlen(pContent)</span><span style="color: #000000;">*</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(TCHAR));<br><br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">NT_SUCCESS(ntStatus))<br>{<br>KdPrint((\</span><span style="color: #000000;">"</span><span style="color: #000000;">WritetoLogFile&nbsp;failed&nbsp;-&nbsp;%X\\n\</span><span style="color: #000000;">"</span><span style="color: #000000;">,ntStatus));<br>ZwClose(pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">hLogFileHandle);<br>IoDeleteDevice(pFdo);<br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ntStatus;<br>}<br><br>pdx</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">pLowerDeviceObject&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;IoAttachDeviceToDeviceStack(pFdo,pPdo);<br>pFdo</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;</span><span style="color: #000000;">~</span><span style="color: #000000;">DO_DEVICE_INITIALIZING;<br><br></span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ntStatus;<br>}<br></span></div>
<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #000000;">ZwCreateFile(FileHandle,&nbsp;<br>GENERIC_WRITE</span><span style="color: #000000;">|</span><span style="color: #000000;">SYNCHRONIZE</span><span style="color: #000000;">|</span><span style="color: #000000;">GENERIC_READ,&nbsp;<br></span><span style="color: #000000;">&amp;</span><span style="color: #000000;">ObjectAttributes,&nbsp;<br></span><span style="color: #000000;">&amp;</span><span style="color: #000000;">IoStatusBlock,&nbsp;<br></span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;<br>FILE_ATTRIBUTE_NORMAL,&nbsp;<br>FILE_SHARE_DELETE,&nbsp;<br>FILE_OPEN_IF,&nbsp;<br>FILE_SYNCHRONOUS_IO_NONALERT,&nbsp;<br>NULL,&nbsp;<br></span><span style="color: #000000;">0</span><span style="color: #000000;">);&nbsp;</span></div><img src ="http://www.cppblog.com/momoxiao/aggbug/107320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-05 23:50 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/05/107320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（zz）提取硬盘ID </title><link>http://www.cppblog.com/momoxiao/archive/2010/02/05/107318.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 15:45:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/05/107318.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107318.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/05/107318.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107318.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107318.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: #include&nbsp;&lt;windows.h&gt;&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;stdio.h&gt;&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;string.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**************************************/&nbs...&nbsp;&nbsp;<a href='http://www.cppblog.com/momoxiao/archive/2010/02/05/107318.html'>阅读全文</a><img src ="http://www.cppblog.com/momoxiao/aggbug/107318.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-05 23:45 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/05/107318.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（zz）实战DeviceIoControl 系列 之四：获取硬盘的详细信息</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/05/107317.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 05 Feb 2010 15:42:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/05/107317.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107317.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/05/107317.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107317.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107317.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 实战DeviceIoControl 之四：获取硬盘的详细信息用IOCTL_DISK_GET_DRIVE_GEOMETRY或IOCTL_STORAGE_GET_MEDIA_TYPES_EX只能得到很少的磁盘参数，我想获得包括硬盘序列号在内的更加详细的信息，有什么办法呀？确实，用你所说的I/O控制码，只能得到最基本的磁盘参数。获取磁盘出厂信息的I/O控制码，微软在VC/MFC环境中没有开放，在DD...&nbsp;&nbsp;<a href='http://www.cppblog.com/momoxiao/archive/2010/02/05/107317.html'>阅读全文</a><img src ="http://www.cppblog.com/momoxiao/aggbug/107317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-05 23:42 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/05/107317.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zz]设备对象种类</title><link>http://www.cppblog.com/momoxiao/archive/2010/02/03/107110.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Wed, 03 Feb 2010 08:17:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/02/03/107110.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/107110.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/02/03/107110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/107110.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/107110.html</trackback:ping><description><![CDATA[<h5>&nbsp;
<p><span>一个驱动程序为它所控制的每个设备产生设备对象，设备对象代表驱动程序的设备。从</span><span>PnP</span><span>的角度看有三种设备对象：</span></p>
<p><span><span>n&nbsp;</span></span><span>物理设备对象（</span><span>PDO</span><span>）</span><span>---</span><span>代表一个总线驱动程序的总线上的设备</span></p>
<p><span><span>n&nbsp;</span></span><span>功能设备对象（</span><span>FDO</span><span>）</span><span>---</span><span>代表一个功能驱动程序的设备</span></p>
<p><span><span>n&nbsp;</span></span><span>过滤程序设备对象（</span><span>Filter DO</span><span>）</span><span>---</span><span>代表一个过滤器驱动程序的设备</span></p>
<p><span>这三种设备对象都是</span><span>DEVICE_OBJECT</span><span>类型，但是使用方式不同并有不同的设备扩展。</span></p>
<p><span>通过产生一设备对象（</span><strong><span>IoCreateDevice</span></strong><span>）并将其附着到设备堆栈（</span><strong><span>IoAttachDeviceToDevice_Stack</span></strong><span>），驱动程序将其本身添加到处理设备的</span><span>I/O</span><span>驱动程序堆栈，</span><strong><span>IoAttachDeviceToDeviceStack</span></strong><span>决定设备堆栈当前的顶层和附着新的设备对象到设备堆栈的顶层。</span></p>
<p><span>图</span><span>1.7</span><span>给出了设备对象的可能种类，该设备对象可附着于设备堆栈里，表示处理一个设备的</span><span>I/O</span><span>请求的驱动程序。</span></p>
<p><span>这一部分描述了每一类的设备对象并注意到何时产生该类。参看第</span><span>2</span><span>章获得关于在必要的</span><span>PnP</span><span>驱动程序例程里产生设备对象的细节信息，要获得</span><span>PnP</span><span>设备枚举的更多信息，参见第</span><span>2</span><span>部分。</span></p>
<p><span>开始于图</span><span>1.7</span><span>的底部：</span></p>
<p><span><span>n&nbsp;</span></span><span>总线驱动程序为总线上它所枚举的每个设备产生</span><span>PDO</span><span>。</span></p>
<p><span>当总线驱动程序枚举其设备时，它为每个子设备产生</span><span>PDO</span><span>。总线驱动程序枚举一设备为</span><span>PnP</span><span>管理器的</span><strong><span>BusRelations</span></strong><span>响应一个</span><span>IRP_MN_QUERY_DEVICE_RELATIONS</span><span>请求。如果自从最近一次总线驱动程序响应</span><strong><span>BusRelations</span></strong><span>的查询关系请求以来（或者这是机器被引导以来第一次查询关系）设备已经添加到总线上，则总线驱动程序为每个子设备产生一个</span><span>PDO</span><span>。</span></p>
<p><span>PDO</span><span>表示了总线驱动程序的设备，其他内核模式系统组件也和它一样，如电源管理器、</span><span>PnP</span><span>管理器和</span><span>I/O</span><span>管理器。</span></p>
<p><span>一个设备其他的驱动程序附着于</span><span>PDO</span><span>顶端的设备对象，但是</span><span>PDO</span><span>一直在设备堆栈的底端。</span></p>
<p><span><span>n&nbsp;</span></span><span>可选择的总线过滤器驱动程序为它们过滤的每个设备产生过滤程序</span><span>DO</span><span>。</span></p>
<p><span>当</span><span>PnP</span><span>管理器在</span><strong><span>BusRelations</span></strong><span>列表里发现一个新设备时，它决定是否有该设备的任何总线过滤器驱动程序。如果是这样的话，对每个这样的驱动程序</span><span>PnP</span><span>管理器确保它们被装载（如果需要调用</span><span>DriverEntry</span><span>）并调用驱动程序</span><span>AddDevice</span><span>例程。如果总线过滤器驱动程序为这个设备过滤操作，过滤器驱动程序产生一个设备对象并附着它到</span><span>AddDevice</span><span>例程里的设备堆栈上。如果不止一个总线过滤器驱动程序存在，且与这个设备相关，每个这样的过滤器驱动程序产生并附着于它自己的设备对象。</span></p>
<p><span><span>n&nbsp;</span></span><span>可选择的，低层过滤器驱动程序为它们过滤的每个设备产生过滤程序</span><span>DO</span><span>。</span></p>
<p><span>如果一可选择的低层过滤器驱动程序由于这个设备的原因而存在，</span><span>PnP</span><span>管理器确信在总线驱动程序和任何总线过滤器驱动程序之后装载了这样的驱动程序。</span><span>PnP</span><span>管理器调用过滤器驱动程序的</span><span>AddDevice</span><span>例程，在它的</span><span>AddDevice</span><span>例程里，低层的过滤器驱动程序为设备产生一个过滤程序</span><span>DO</span><span>且附着它到设备堆栈里。如果不止一个低层过滤器驱动程序存在，每个这样的驱动程序将产生并附着它自己的过滤程序</span><span>DO</span><span>。</span></p>
<p><span><span>n&nbsp;</span></span><span>功能驱动程序为设备产生一个</span><span>FDO</span><span>。</span></p>
<p><span>PnP</span><span>管理器确信已安装了设备的功能驱动程序并调用功能驱动程序的</span><span>AddDevice</span><span>例程，功能驱动程序产生一个</span><span>FDO</span><span>并附着它到设备堆栈里。</span></p>
<p><span><span>n&nbsp;</span></span><span>可选择的，顶层过滤器驱动程序为它们过滤的每个设备产生过滤程序</span><span>DO</span><span>。</span></p>
<p><span>如果任何可选择的，顶层过滤器驱动程序为设备而存在，</span><span>PnP</span><span>管理器确信在功能驱动程序调用它们的</span><span>AddDevice</span><span>例程之后被安装，每个这样的过滤器驱动程序附着它的设备对象到设备堆栈。</span></p>
<p><span>总之，设备堆栈包括每一驱动程序的设备对象，该驱动程序参与了特定设备的</span><span>I/O</span><span>处理。父总线驱动程序有一个</span><span>PDO</span><span>，功能驱动程序有一个</span><span>FDO</span><span>，每一个可选择的过滤器驱动程序有一个过滤程序</span><span>DO</span><span>。</span></p>
<p><span>注意到所有的设备</span><span>---</span><span>总线适配器</span><span>/</span><span>控制器设备和非总线设备</span><span>---</span><span>在它们的设备堆栈里有一个</span><span>PDO</span><span>和</span><span>FDO</span><span>。总线适配器</span><span>/</span><span>控制器的</span><span>PDO</span><span>由父总线的总线驱动程序产生。例如，如果一个</span><span>SCSI</span><span>适配器插入一个</span><span>PCI</span><span>总线，</span><span>PCI</span><span>总线驱动程序为</span><span>SCSI</span><span>适配器产生一个</span><span>PDO</span><span>。</span></p>
<p><span>如果一个设备正以原始模式使用，则没有功能驱动程序或过滤器驱动程序（没有</span><span>FDO</span><span>或过滤程序</span><span>DO</span><span>）。此时还有父总线驱动程序的一个</span><span>PDO</span><span>和零个或更多总线过滤程序</span><span>DO</span><span>。</span></p>
<p><span>要获取哪一个驱动程序例程负责产生和附着设备对象的信息，参看第</span><span>2</span><span>章。</span></p>
<p><span>设备堆栈和一些额外信息构成了一个</span><span>devnode</span><span>设备。在一个设备的</span><span>devnode</span><span>里，</span><span>PnP</span><span>管理器保留诸如是否设备已经启动和哪一个驱动程序，如有，登记通知设备上的改变。内核调试程序<strong>！</strong></span><strong><span>devnode</span></strong><span>命令显示了关于一个</span><span>devnode</span><span>的信息。</span></p>
<a name="_Toc490715603"><span></span></a></h5><img src ="http://www.cppblog.com/momoxiao/aggbug/107110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-02-03 16:17 <a href="http://www.cppblog.com/momoxiao/archive/2010/02/03/107110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zz]ZwWriteFile</title><link>http://www.cppblog.com/momoxiao/archive/2010/01/15/105774.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Fri, 15 Jan 2010 10:28:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/01/15/105774.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/105774.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/01/15/105774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/105774.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/105774.html</trackback:ping><description><![CDATA[<a href="http://bbs.driverdevelop.com/read.php?tid-21125.html">http://bbs.driverdevelop.com/read.php?tid-21125.html</a><img src ="http://www.cppblog.com/momoxiao/aggbug/105774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-01-15 18:28 <a href="http://www.cppblog.com/momoxiao/archive/2010/01/15/105774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zz]WindowsXP启动过程</title><link>http://www.cppblog.com/momoxiao/archive/2010/01/09/105258.html</link><dc:creator>小默</dc:creator><author>小默</author><pubDate>Sat, 09 Jan 2010 09:32:00 GMT</pubDate><guid>http://www.cppblog.com/momoxiao/archive/2010/01/09/105258.html</guid><wfw:comment>http://www.cppblog.com/momoxiao/comments/105258.html</wfw:comment><comments>http://www.cppblog.com/momoxiao/archive/2010/01/09/105258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/momoxiao/comments/commentRss/105258.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/momoxiao/services/trackbacks/105258.html</trackback:ping><description><![CDATA[&nbsp;<span>从按下计算机开关启动计算机，到登入到桌面完成启动，一共经过了以下几个阶段：</span><span> </span>
<p><span>　　</span><span>1. </span><span>预引导</span><span>(Pre-Boot)</span><span>阶段；</span><span> </span></p>
<p><span>　　</span><span>2. </span><span>引导阶段；</span><span> </span></p>
<p><span>　　</span><span>3. </span><span>加载内核阶段；</span><span> </span></p>
<p><span>　　</span><span>4. </span><span>初始化内核阶段；</span><span> </span></p>
<p><span>　　</span><span>5. </span><span>登录。</span><span> </span></p>
<p>&nbsp;</p>
<p><span>　　每个启动阶段的详细介绍</span><span> </span></p>
<p><strong><span>　　</span><span>a) </span></strong><strong><span>预引导阶段</span><span> </span></strong></p>
<p><span>　　在按下计算机电源使计算机启动，并且在</span><span>Windows XP</span><span>专业版操作系统启动之前这段时间，我们称之为预引导（</span><span>Pre-Boot</span><span>）阶段，在这个阶段里，计算机首先运行</span><span>Power On Self Test</span><span>（</span><span>POST</span><span>），</span><span>POST</span><span>检测系统的总内存以及其他硬件设备的现状。如果计算机系统的</span><span>BIOS(</span><span>基础输入</span><span>/</span><span>输出系统</span><span>)</span><span>是即插即用的，那么计算机硬件设备将经过检验以及完成配置。计算机的基础输入</span><span>/</span><span>输出系统（</span><span>BIOS</span><span>）定位计算机的引导设备，然后</span><span>MBR(Master Boot Record)</span><span>被加载并运行。在预引导阶段，计算机要加载</span><span>Windows XP</span><span>的</span><span>NTLDR</span><span>文件。</span><span> </span></p>
<p><strong><span>　　</span><span>b) </span></strong><strong><span>引导阶段</span><span> </span></strong></p>
<p><span>Windows XP Professional</span><span>引导阶段包含</span><span>4</span><span>个小的阶段。</span><span> </span></p>
<p><span>首先，计算机要经过初始引导加载器阶段（</span><span>Initial Boot Loader</span><span>），在这个阶段里，</span><span>NTLDR</span><span>将计算机微处理器从实模式转换为</span><span>32</span><span>位平面内存模式。在实模式中，系统为</span><span>MS-DOS</span><span>保留</span><span>640kb</span><span>内存，其余内存视为扩展内存，而在</span><span>32</span><span>位平面内存模式中，系统（</span><span>Windows XP Professional</span><span>）视所有内存为可用内存。接着，</span><span>NTLDR</span><span>启动内建的</span><span>mini-file system drivers</span><span>，通过这个步骤，使</span><span>NTLDR</span><span>可以识别每一个用</span><span>NTFS</span><span>或者</span><span>FAT</span><span>文件系统格式化的分区，以便发现以及加载</span><span>Windows XP Professional</span><span>，到这里，初始引导加载器阶段就结束了。</span><span> </span></p>
<p><span>　　接着系统来到了操作系统选择阶段，如果计算机安装了不止一个操作系统（也就是多系统），而且正确设置了</span><span>boot.ini</span><span>使系统提供操作系统选择的条件下，计算机显示器会显示一个操作系统选单，这是</span><span>NTLDR</span><span>读取</span><span>boot.ini</span><span>的结果。</span></p>
<p><span>　　在</span><span>boot.ini</span><span>中，主要包含以下内容：</span><span> </span></p>
<p><span>　　</span><span>[boot loader] </span></p>
<p><span>　　</span><span>timeout=30 </span></p>
<p><span>　　</span><span>default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS </span></p>
<p><span>　　</span><span>[operating systems] </span></p>
<p><span>　　</span><span>multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect </span></p>
<p><span>　　</span><span>multi(0)disk(0)rdisk(0)partition(2)\WINNT="Windows Windows 2000 Professional" </span></p>
<p><span>　　其中，</span><span>multi(0)</span><span>表示磁盘控制器，</span><span>disk(0)rdisk(0)</span><span>表示磁盘，</span><span>partition(x)</span><span>表示分区。</span><span>NTLDR</span><span>就是从这里查找</span><span>Windows XP Professional</span><span>的系统文件的位置的。（</span><span>*</span><span>本文不会更详细地讲解</span><span>boot.ini</span><span>的组成结构，因为其与本主题关系不大，如果想了解，可以到一些专门的网站处查询相关信息。）如果在</span><span>boot.ini</span><span>中只有一个操作系统选项，或者把</span><span>timeout</span><span>值设为</span><span>0</span><span>，则系统不出现操作系统选择菜单，直接引导到那个唯一的系统或者默认的系统。在选择启动</span><span>Windows XP Professional</span><span>后，操作系统选择阶段结束，硬件检测阶段开始。</span><span> </span></p>
<p><span>　　在硬件检测阶段中，</span><span>ntdetect.com</span><span>将收集计算机硬件信息列表并将列表返回到</span><span>NTLDR</span><span>，这样做的目的是便于以后将这些硬件信息加入到注册表</span><span>HKEY_LOCAL_MACHINE</span><span>下的</span><span>hardware</span><span>中。</span><span> </span></p>
<p><span>　　硬件检测完成后，进入配置选择阶段。如果计算机含有多个硬件配置文件列表，可以通过按上下按钮来选择。如果只有一个硬件配置文件，计算机不显示此屏幕而直接使用默认的配置文件加载</span><span>Windows XP</span><span>专业版。</span><span> </span></p>
<p><span>引导阶段结束。在引导阶段，系统要用到的文件一共有：</span><span>NTLDR</span><span>，</span><span>Boot.ini</span><span>，</span><span>ntdetect.com</span><span>，</span><span>ntokrnl.exe</span><span>，</span><span>Ntbootdd.sys</span><span>，</span><span>bootsect.dos</span><span>（可选的）。</span></p>
<p><strong><span>c) </span></strong><strong><span>加载内核阶段</span></strong></p>
<p><span>在加载内核阶段，</span><span>ntldr</span><span>加载称为</span><span>Windows XP</span><span>内核的</span><span>ntokrnl.exe</span><span>。系统加载了</span><span>Windows XP</span><span>内核但是没有将它初始化。接着</span><span>ntldr</span><span>加载硬件抽象层（</span><span>HAL</span><span>，</span><span>hal.dll</span><span>），然后，系统继续加载</span><span>HKEY_LOCAL_MACHINE\system</span><span>键，</span><span>NTLDR</span><span>读取</span><span>select</span><span>键来决定哪一个</span><span>Control Set</span><span>将被加载。控制集中包含设备的驱动程序以及需要加载的服务。</span><span>NTLDR</span><span>加载</span><span>HKEY_LOCAL_MACHINE\system\service\...</span><span>下</span><span>start</span><span>键值为</span><span>0</span><span>的最底层设备驱动。当作为</span><span>Control Set</span><span>的镜像的</span><span>Current Control Set</span><span>被加载时，</span><span>ntldr</span><span>传递控制给内核，初始化内核阶段就开始了。</span></p>
<p><strong><span>d) </span></strong><strong><span>初始化内核阶段</span></strong></p>
<p><span>在初始化内核阶段开始的时候，彩色的</span><span>Windows XP</span><span>的</span><span>logo</span><span>以及进度条显示在屏幕中央，在这个阶段，系统完成了启动的</span><span>4</span><span>项任务：</span></p>
<p><span>内核使用在硬件检测时收集到的数据来创建注册表中</span><span>HKEY_LOCAL_MACHINE\ HARDWARE</span><span>键。</span></p>
<p><span>内核通过引用</span><span>HKEY_LOCAL_MACHINE\system\Current</span><span>的默认值复制</span><span>Control Set</span><span>来创建了</span><span>Clone Control Set</span><span>。</span><span>Clone Control Set</span><span>配置是计算机数据的备份，不包括启动中的改变，也不会被修改。</span></p>
<p><span>系统完成初始化以及加载设备驱动程序，内核初始化那些在加载内核阶段被加载的底层驱动程序，然后内核扫描</span><span>HKEY_LOCAL_MACHINE\system\CurrentControlSet\service\...</span><span>下</span><span>start</span><span>键值为</span><span>1</span><span>的设备驱动程序。这些设备驱动程序在加载的时候便完成初始化，如果有错误发生，内核使用</span><span>ErrorControl</span><span>键值来决定如何处理，值为</span><span>3</span><span>时，错误标志为危机</span><span>/</span><span>关键，系统初次遇到错误会以</span><span>LastKnownGood Control Set</span><span>重新启动，如果使用</span><span>LastKnownGood Control Set</span><span>启动仍然产生错误，系统报告启动失败，错误信息将被显示，系统停止启动；值为</span><span>2</span><span>时错误情况为严重，系统启动失败并且以</span><span>LastKnownGood Control Set</span><span>重新启动，如果系统启动已经在使用</span><span>LastKnownGood</span><span>值，它会忽略错误并且继续启动；当值是</span><span>1</span><span>的时候错误为普通，系统会产生一个错误信息，但是仍然会忽略这个错误并且继续启动；当值是</span><span>0</span><span>的时候忽略，系统不会显示任何错误信息而继续运行</span></p>
<p><span>Session Manager</span><span>启动了</span><span>Windows XP</span><span>高级子系统以及服务，</span><span>Session Manager</span><span>启动控制所有输入、输出设备以及访问显示器屏幕的</span><span>Win32</span><span>子系统以及</span><span>Winlogon</span><span>进程，初始化内核完毕。</span></p>
<p><strong><span>e) </span></strong><strong><span>登录</span></strong></p>
<p><span>Winlogon.exe</span><span>启动</span><span>Local Security Authority</span><span>，同时</span><span>Windows XP Professional</span><span>欢迎屏幕或者登录对话框显示，这时候，系统还可能在后台继续初始化刚才没有完成的驱动程序。</span></p>
<p><span>提示输入有效的用户名或密码。</span></p>
<p><span>Service Controller</span><span>最后执行以及扫描</span><span>HKEY_LOCAL_MACHINE\SYSTEM\ CurrentControlSet\Servives</span><span>来检查是否还有服务需要加载，</span><span>Service Controller</span><span>查找</span><span>start</span><span>键值为</span><span>2</span><span>或更高的服务，服务按照</span><span>start</span><span>的值以及</span><span>DependOnGroup</span><span>和</span><span>DepandOnService</span><span>的值来加载。</span></p>
<p><span>只有用户成功登录到计算机后，</span><span>Windows XP</span><span>的启动才被认为是完成，在成功登录后，系统拷贝</span><span>Clone Control Set</span><span>到</span><span>LastKnownGood Control Set</span><span>，完成这一步骤后，系统才意味着已经成功引导了。</span></p><img src ="http://www.cppblog.com/momoxiao/aggbug/105258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/momoxiao/" target="_blank">小默</a> 2010-01-09 17:32 <a href="http://www.cppblog.com/momoxiao/archive/2010/01/09/105258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>