﻿<?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++博客-elva-随笔分类-驱动开发</title><link>http://www.cppblog.com/elva/category/4223.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 26 Jul 2008 21:53:32 GMT</lastBuildDate><pubDate>Sat, 26 Jul 2008 21:53:32 GMT</pubDate><ttl>60</ttl><item><title>使用Virtual PC进行Windows内核调试的详细过程</title><link>http://www.cppblog.com/elva/archive/2008/07/23/56975.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 23 Jul 2008 11:06:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/07/23/56975.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/56975.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/07/23/56975.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/56975.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/56975.html</trackback:ping><description><![CDATA[<p>使用WinDbg进行Windows内核调试通常需要两台计算机，一台是Debuggee，一台作为Debugger，又成为Host。使用Virtual PC可以在同一台电脑上进行内核调试，对于某些调试任务来说还是非常有用的。</p>
<p>下面以Virtual PC 2004为例，介绍一下利用Virtual PC进行Windows内核调试的详细过程。</p>
<p>1，下载并安装Virtual PC 2004，从略。</p>
<p>2，启动Virutal PC Console（控制台），创建一台新的虚拟PC，安装向导的提示配置硬盘、内存等参数。</p>
<p>3，在刚才创建的虚拟PC上安装操作系统，这个操作系统应该是你要调试的Windows版本。比如你想调试你的驱动程序在Windows Server 2003上出现的问题，那么就安装Windows Server 2003。我们以Windows 2000为例。</p>
<p>4，配置虚拟PC的串行口，在Virtual PC的控制台中选择Windows 2000，然后点击Settings按钮弹出设置对话框，然后在左侧的列表中（如下图）选择COM1。</p>
<p><img src="http://advdbg.com/img/inset/virpc/set.jpg"></p>
<p>右侧选择Named Pipe选项，即使用命名管道来模拟串行口，然后输入管道的完整名称：<a href="file://./pipe/com_1"><u><font color=#0000ff>\\.\pipe\com_1</font></u></a>，com_1可以为其它名称，但是前面的部分应该保持不变。</p>
<p>5，启动虚拟PC中的Windows 2000，然后进入命令行窗口，执行如下命令以便在启动菜单中增加调试选项：</p>
<p>c:</p>
<p>cd\</p>
<p>attrib -r -h</p>
<p>edit boot.ini</p>
<p>然后将其最末一行复制，并加入调试选项，成为为如下状态：</p>
<p><img src="http://advdbg.com/img/inset/virpc/boot.jpg"></p>
<p>6，在虚拟PC中选择重新启动Windows 2000，当出现启动菜单时，按方向键使其停止自动计时，等待在这里。</p>
<p><img src="http://advdbg.com/img/inset/virpc/wait.jpg"></p>
<p>7，在主机（debugger）上准备启动WinDbg，考虑每次输入命令行参数太麻烦，所以建议建立一个如下内容的批处理文件，并将其放到与WinDbg.exe同位置的目录中。</p>
<p>windbg -k com:pipe,port=\\.\pipe\com_1</p>
<p>8，运行批处理文件，使其也进入等待状态：</p>
<p><img src="http://advdbg.com/img/inset/virpc/wait_dbg.jpg"></p>
<p>9，切换到虚拟PC窗口，选择带有&#8220;Debug Enabled&#8221;的一项然后回车启动。</p>
<p>10，切换到WinDbg窗口并观察，如果一切顺利，那么会有如下类似信息输出：</p>
<p>Connected to Windows 2000 2195 x86 compatible target, ptr64 FALSE<br>Kernel Debugger connection established.<br>Symbol search path is: SRV*c:\symbols*http://msdl.microsoft.com/download/symbols<br>Executable search path is: <br>Windows 2000 Kernel Version 2195 UP Free x86 compatible<br>Kernel base = 0x80400000 PsLoadedModuleList = 0x8046a4c0<br>System Uptime: not available</p>
<p>11，见到如上信息就说明WinDbg已经与虚拟PC中运行的Windows 2000成功建立调试对话了。如果想感受一下将Windows控制于股掌之中的快感，那么就按下Ctrl+Break，随着按键发出，Windows 2000会被立刻定住。WinDbg中会显示如下信息：</p>
<p>*******************************************************************************<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp; You are seeing this message because you pressed either&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CTRL+C (if you run kd.exe) or,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CTRL+BREAK (if you run WinDBG),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; on your debugger machine's keyboard.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THIS IS NOT A BUG OR A SYSTEM CRASH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>* If you did not intend to break into the debugger, press the "g" key, then&nbsp;&nbsp; *<br>* press the "Enter" key now.&nbsp; This message might immediately reappear.&nbsp; If it *<br>* does, press "g" and "Enter" again.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>*******************************************************************************<br>此时WinDbg的命令提示符区会显示一段时间*BUSY*（或者其它无效状态，老本本的WinDbg），这是因为WinDbg在寻找调试符号。</p>
<p><img src="http://advdbg.com/img/inset/virpc/break.jpg"><br>在你非常熟悉以上过程之后，其实可以不完全拘泥以上过程的，&nbsp;比如可以先让Windows 2000以调试选项运行起来，然后再运行WinDbg。</p>
<p>最后再介绍几种常见的失败情况：</p>
<p>1）启动WinDbg，但是出现下图所示的错误信息，Win32 error 2，即指定的文件名找不到，这是因为虚拟PC还没有启动，还没有创建这个管道<a href="file://\\.\pipe\com_1"><u><font color=#0000ff>\\.\pipe\com_1</font></u></a>， 系统中不存在这样的文件。应该运行虚拟PC，哪怕只到启动选项也可以，便不会再有这个错误了。</p>
<p><img src="http://advdbg.com/img/inset/virpc/file_not.jpg"></p>
<img src ="http://www.cppblog.com/elva/aggbug/56975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-07-23 19:06 <a href="http://www.cppblog.com/elva/archive/2008/07/23/56975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The KLOG Rootkit:A Walk-through</title><link>http://www.cppblog.com/elva/archive/2008/05/14/49815.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Wed, 14 May 2008 05:45:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/05/14/49815.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/49815.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/05/14/49815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/49815.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/49815.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我们的叫做KLOG的键盘监视例子，是Clandestiny所写的并在在www.rootkit.com上发表了。下面我们来浏览分析一下她的代码。ps:一个比较流行的键盘分层过滤驱动可以在www.sysinternals.com上找到。名字为ctrl2cap。KLOG就是在它的基础上完成的。ROOTKIT.COM这个程序的介绍能在下面找到:www.rootkit.com/newsread.ph...&nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2008/05/14/49815.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/49815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-05-14 13:45 <a href="http://www.cppblog.com/elva/archive/2008/05/14/49815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用钩子技术控制进程创建</title><link>http://www.cppblog.com/elva/archive/2008/04/08/46491.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 08 Apr 2008 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/04/08/46491.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/46491.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/04/08/46491.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/46491.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/46491.html</trackback:ping><description><![CDATA[05年的老文章了,今天才看到,一直想做而没有做出来的东西,差距啊...<br>修正原文一些翻译不恰当的地方<br><br>原英文地址:<br><a href="http://www.codeproject.com/KB/system/soviet_protector.aspx">http://www.codeproject.com/KB/system/soviet_protector.aspx</a><br><br><br><a href="http://www.cppblog.com/Files/elva/drivers/soviet_protector_src.zip"><a href="http://www.codeproject.com/KB/system/soviet_protector/soviet_protector_src.zip">Download source files - 10.8 Kb</a> </a><br><a href="http://www.cppblog.com/Files/elva/drivers/soviet_protector_demo.zip"><a href="http://www.codeproject.com/KB/system/soviet_protector/soviet_protector_demo.zip">Download demo project - 12.1 Kb</a> </a><br><br>一、 简介
<p>　　最近，我了解到一个叫做Sanctuary的相当有趣的安全产品。它能够阻止任何程序的运行-这些程序没有显示在软件列表中-该表中的程序被允许在一个特定的机器上运行。结果，PC用户得到保护而免于各种插件间谍软件、蠕虫和特洛伊木马的侵袭-就算能够进入他/她的计算机，它们也没有机会执行，并因此没有机会对该机器造成任何损害。当然，我觉得这个特征相当有趣；并且，在稍作思考以后，我就有了一个自己的实现。因此，本文将描述如何通过钩住本机API的方式来实现监控一个进程的创建并在系统级上对之进行控制。</p>
<p>　　本文大胆假设，目标进程是以一种用户模式(外壳函数，CreateProcess()，用一系列的本机API调用的手工的进程创建，等等)创建的。尽管从理论上，一个进程能够以内核方式启动；不过从实际来看，如此的可能性是可以忽略不计的，因此我们不必为此担心。为什么？请逻辑地思考一下-为了以内核方式启动一个进程，用户必须装载一个驱动程序，该驱动程序反过来首先要暗示某种用户模式代码的执行。因此，为了防止未被授权程序的执行，我们可以安全地在系统级上以用户模式限制我们自己控制的进程的创建。</p>
<p>　　二、 定义策略</p>
<p>　　首先让我们明确，之所以这样做的目的是为了在系统级上监视和控制进程创建。</p>
<p>　　进程创建是一件相当复杂的事情-它包含相当多的工作(如果你不相信我，可以反汇编CreateProcess()，这样你就会亲眼看到这点)。为了启动一个进程，可以使用下列步骤：</p>
<p>　　1.可执行文件必须被以FILE_EXECUTE存取方式打开。</p>
<p>　　2.可执行映像必须被装载进RAM。</p>
<p>　　3.必须建立进程执行对象(EPROCESS，KPROCESS和PEB结构)。</p>
<p>　　4.必须为新建进程分配地址空间。</p>
<p>　　5.必须建立进程的主线程的线程执行对象(ETHREAD，KTHREAD和TEBstructures)。</p>
<p>　　6.必须为主线程分配堆栈。</p>
<p>　　7.必须建立进程的主线程的执行上下文。</p>
<p>　　8.必须通知Win32子系统有关该新进程的创建情况。</p>
<p>　　为确保这些步骤中的任何一步的成功，所有其前面的步骤必须是成功执行的(你不能够在没有一个可执行区句柄的情况下建立一个可执行进程对象；没有文件句柄的情况下你无法映射一个可执行区，等等)。因此，如果我们决定退出任何这些步骤，所有后面的步骤也会失败，以至于整个进程创建会失败。上面所有的步骤都可以通过调用某些本机API函数的方式来实现，这是可以理解的。因此，为了监视和控制进程创建，我们所有要做的就是钩住这些API函数-它们无法旁路掉要创建一新进程所要执行的代码。</p>
<p>　　我们应该钩住哪些本机API函数呢?尽管NtCreateProcess()似乎是问题的最显然的答案，但是，这个答案是错误的-有可能不需要调用这个函数也可以创建一个新的进程。例如，CreateProcess()可以在不调用NtCreateProcess()的情况下创建与进程相关的内核模式结构.因此，这样以来钩住NtCreateProcess()对我们毫无帮助。</p>
<p>　　为了监视进程的创建，我们必须钩住NtCreateFile()和NtOpenFile()，或者NtCreateSection()之中的一个,-不经调用这些API是绝对无法运行任何可执行文件的。如果我们决定监视对NtCreateFile()和NtOpenFile()的调用，那么我们必须区别开进程创建和常规的文件IO操作。这项任务并不总是那么容易。例如，如果一些可执行文件正在被以FILE_ALL_ACCESS存取方式打开，我们该怎么办？这仅是一个IO操作还是一个进程创建的一部分？在这点上，是很难判断的-我们需要了解调用线程下一步要干什么。因此，钩住NtCreateFile()和NtOpenFile()可能不是最好的选择。</p>
<p>　　钩住NtCreateSection()是更为合理的-如果我们在发生把可执行文件映射为映像(SEC_IMAGE 属性)的请求发生时拦截对NtCreateSection()的调用,结合允许执行页面保护的请求；那么，我们可以确信该进程将要被启动。在这一点上，我们是能够作出决定，如果我们不想该进程被创建，可以让NtCreateSection()返回STATUS_ACCESS_DENIED。因此，为了完全控制目标机器上的进程创建，所有我们要做的是在系统级上钩住NtCreateSection()。</p>
<p>　　象来自于ntdll.dll中的任何其它代理一样，NtCreateSection()用服务索引加载EAX，使EDX指向函数参数，并且把执行权传递到KiDispatchService()内核模式例程(这是通过Windows NT/2000中的INT 0x2E指令或者Windows XP下的SYSENTER指令实现的)。在校验完函数参数之后，KiDispatchService()把执行权传递到服务的实际实现部分-它的地址可用于服务描述表(指向这个表的指针由ntoskrnl.exe作为KeServiceDescriptorTable变量所输出，所以它对于内核模式驱动程序是可用的)中。服务描述表通过下列结构所描述：<br>&nbsp;</p>
<p>　　struct SYS_SERVICE_TABLE { </p>
<p>　　void **ServiceTable; </p>
<p>　　unsigned long CounterTable; </p>
<p>　　unsigned long ServiceLimit; </p>
<p>　　void **ArgumentsTable; </p>
<p>　　}; <br><br></p>
<p>　　这个结构中的ServiceTable字段指向一个数组-它拥有所有实现系统服务的函数的地址。因此，为了在系统级上钩住任何本机API函数，所有我们必须做的是把我们的代理函数的地址写入被KeServiceDescriptorTable的ServiceTable字段所指向的数组的第i个入口(i是服务索引)。</p>
<p>　　至此，看起来我们已了解了在系统级上监视和控制进程创建的一切。现在让我们开始实际的工作。</p>
<strong>三、 控制进程创建<br><br></strong>　　我们的解决方案由一个内核模式驱动程序和一个用户模式应用程序组成。为了开始监视进程创建，我们的应用程序要把服务索引（相应于NtCreateSection()）以及交换缓冲区的地址传递到我们的驱动程序。这是由下列代码所完成的：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>//打开设备<br>device=CreateFile("\\.\PROTECTOR",GENERIC_READ|GENERIC_WRITE, <br>0,0,OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM,0);<br>//得到NtCreateSection的索引并把它连同输出缓冲区的地址传递给设备<br>DWORD * addr=(DWORD *)<br>(1+(DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtCreateSection"));<br>ZeroMemory(outputbuff,256);<br>controlbuff[0]=addr[0];<br>controlbuff[1]=(DWORD)&amp;outputbuff[0];<br>DeviceIoControl(device,1000,controlbuff,256,controlbuff,256,&amp;dw,0);</td>
        </tr>
    </tbody>
</table>
<br>　　此代码是显然的-唯一需要注意的是我们得到服务索引的方式。所有来自于ntdll.dll的代理都从一行代码MOV EAX,ServiceIndex开始-它可以适用于任何版本和风味的Windows NT。这是一条5字节长的指令，以MOV EAX操作码作第一字节，服务索引作为留下的4字节。因此，为了得到相应于一些特别的本机API函数的服务索引，所有你要做的是从该地址读取4个字节，-位于从这个代理开始1字节距离的地方。<br><br>　　现在让我们看一下我们的驱动程序做什么，当它收到来自我们的应用程序的IOCTL时：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>NTSTATUS DrvDispatch(IN PDEVICE_OBJECT device,IN PIRP Irp)<br>{<br>　UCHAR*buff=0; ULONG a,base;<br>　PIO_STACK_LOCATION loc=IoGetCurrentIrpStackLocation(Irp);<br>　if(loc-&gt;Parameters.DeviceIoControl.IoControlCode==1000)<br>　{<br>　　buff=(UCHAR*)Irp-&gt;AssociatedIrp.SystemBuffer;<br>　　//钩住服务调度表<br>　　memmove(&amp;Index,buff,4);<br>　　a=4*Index+(ULONG)KeServiceDescriptorTable-&gt;ServiceTable;<br>　　base=(ULONG)MmMapIoSpace(MmGetPhysicalAddress((void*)a),4,0);<br>　　a=(ULONG)&amp;Proxy;<br>　　_asm<br>　　{<br>　　　mov eax,base<br>　　　mov ebx,dword ptr[eax]<br>　　　mov RealCallee,ebx<br>　　　mov ebx,a<br>　　　mov dword ptr[eax],ebx<br>　　}<br>　　MmUnmapIoSpace(base,4);<br>　　memmove(&amp;a,&amp;buff[4],4);<br>　　output=(char*)MmMapIoSpace(MmGetPhysicalAddress((void*)a),256,0);<br>　}<br>　Irp-&gt;IoStatus.Status=0;<br>　IoCompleteRequest(Irp,IO_NO_INCREMENT);<br>　return 0;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　正如你所见，这里没有什么特别的-我们只是通过MmMapIoSpace()来把交换缓冲区映射到内核中，另外把我们的代理函数的地址写到服务表(当然，我们这是在把实际的服务执行的地址保存到全局变量RealCallee以后这样做的)。为了改写服务表的适当入口，我们通过MmMapIoSpace()来映射目标地址。为什么我们要这样做？不管怎么说，我们已经可以存取服务表了，不是吗？问题是，服务表可能驻留在一段只读内存中。因此，我们必须检查一下是否我们有对目标空间写的权限，而如果我们没有这个权限，那么在改写服务表之前，我们必须改变页面保护。你不认为这样以来工作太多了吗？因此，我们仅用MmMapIoSpace()来映射我们的目标地址，这样以来，我们就不必担心任何的页面保护问题了-从现在开始，我们假定已有到目标页面写的权限了。现在让我们看一下我们的代理函数:<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>//这个函数用来确定是否我们应该允许NtCreateSection()调用成功<br>ULONG __stdcall check(PULONG arg)<br>{<br>　HANDLE hand=0;PFILE_OBJECT file=0;<br>　POBJECT_HANDLE_INFORMATION info;ULONG a;char*buff;<br>　ANSI_STRING str; LARGE_INTEGER li;li.QuadPart=-10000;<br>　//检查标志。如果所要求的存取方式不是PAGE_EXECUTE,<br>　//这并不要紧<br>　if((arg[4]&amp;0xf0)==0)return 1;<br>　if((arg[5]&amp;0x01000000)==0)return 1;<br>　//经由文件句柄得到文件名<br>　hand=(HANDLE)arg[6];<br>　ObReferenceObjectByHandle(hand,0,0,KernelMode,&amp;file,&amp;info);<br>　if(!file)return 1;<br>　　RtlUnicodeStringToAnsiString(&amp;str,&amp;file-&gt;FileName,1);<br>　　a=str.Length;buff=str.Buffer;<br>　　while(1)<br>　　{<br>　　　if(buff[a]=='.'){a++;break;}<br>　　　a--;<br>　　}<br>　　ObDereferenceObject(file);<br>　　//如果它是不可执行的,这也不要紧<br>　　//返回1<br>　　if(_stricmp(&amp;buff[a],"exe")){RtlFreeAnsiString(&amp;str);return 1;}<br>　　　//现在，我们要询问用户的选择。<br>　　　//把文件名写入缓冲区，并等待直到用户显示响应<br>　　　//(第一个DWORD为1意味着我们可以继续)<br>　　　//同步存取该缓冲区<br>　　　KeWaitForSingleObject(&amp;event,Executive,KernelMode,0,0);<br>　　　//把缓冲区的前两个DWORD置为0，<br>　　　//把字符串复制到该缓冲区中，并循环下去，直到用户把每一个<br>　　　//DWORD置为1.<br>　　　//第二个DWORD的值指明用户的响应<br>　　strcpy(&amp;output[8],buff);<br>　　RtlFreeAnsiString(&amp;str);<br>　　a=1;<br>　　memmove(&amp;output[0],&amp;a,4);<br>　　while(1)<br>　　{<br>　　　KeDelayExecutionThread(KernelMode,0,&amp;li);<br>　　　memmove(&amp;a,&amp;output[0],4);<br>　　　if(!a)break;<br>　　}<br>　　memmove(&amp;a,&amp;output[4],4);<br>　　KeSetEvent(&amp;event,0,0);<br>　　return a;<br>　}<br>　//仅保存执行上下文并调用check() <br>　_declspec(naked) Proxy()<br>　{<br>　　_asm{<br>　　　//保存执行上下文并调用check()<br>　　　//-后面的依赖于check()所返回的值<br>　　　// 如果返回值是1，继续实际的调用。<br>　　　//否则，返回STATUS_ACCESS_DENIED<br>　　　pushfd<br>　　　pushad<br>　　　mov ebx,esp<br>　　　add ebx,40<br>　　　push ebx<br>　　　call check<br>　　　cmp eax,1<br>　　　jne block<br>　　　//继续实际的调用<br>　　　popad<br>　　　popfd<br>　　　jmp RealCallee<br>　　　//返回STATUS_ACCESS_DENIED<br>　　　block:popad<br>　　　mov ebx, dword ptr[esp+8]<br>　　　mov dword ptr[ebx],0<br>　　　mov eax,0xC0000022L<br>　　　popfd<br>　　　ret 32<br>　　}<br>　}</td>
        </tr>
    </tbody>
</table>
<br>　　Proxy()保存寄存器和标志，把一个指向服务参数的指针压入栈中并调用check()。其它的依赖于check()所返回的值。如果check()返回TRUE(也就是，我们想要继续请求)，那么，Proxy()将恢复寄存器和标志，并且把控制权交给服务实现部分。否则，Proxy()将把STATUS_ACCESS_DENIED写入EAX，恢复ESP并返回-从调用者的观点来看，这就象对NtCreateSection()的调用失败一样-以错误状态STATUS_ACCESS_DENIED返回。<br>&nbsp;check()函数是怎样做出决定的？一旦它收到一个指向服务参数的指针参数，它就可以检查这些参数。首先，它检查标志和属性-如果有一部分没有被要求作为一个可执行映像映射，或如果要求的页面保护不允许执行，那么我们可以确定NtCreateSection()调用与进程创建毫无关系。在这种情况下，check()直接返回TRUE。否则，它将检查该潜在文件的扩展-毕竟，SEC_IMAGE属性和允许执行的页面保护可能被要求来映射某个DLL文件。如果该潜在文件不是一个.exe文件，那么，check()将返回TRUE。否则，它给用户模式代码一个作出决定的机会。因此，它仅把文件名和路径写到交换缓冲区，并且对它循环查询，直到它得到响应为止。<br><br>　　在打开我们的驱动程序前，我们的应用程序创建一个运行下面函数的线程：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>void thread()<br>{<br>　DWORD a,x; char msgbuff[512];<br>　while(1)<br>　{<br>　　memmove(&amp;a,&amp;outputbuff[0],4);<br>　　//如果什么也没有，Sleep() 10毫秒并再检查<br>　　if(!a){Sleep(10);continue;}<br>　　//看起来象我们的权限被询问。 <br>　　//如果被怀疑的文件已经存在于空白列表中，<br>　　// 则给出一个积极的响应。<br>　　char*name=(char*)&amp;outputbuff[8];<br>　　for(x=0;x&lt;stringcount;x++)<br>　　{<br>　　　if(!stricmp(name,strings[x])){a=1;goto skip;}<br>　　}<br>　　//要求用户允许运行该程序<br>　　strcpy(msgbuff, "Do you want to run ");<br>　　strcat(msgbuff,&amp;outputbuff[8]);<br>　　//如果用户的答复是积极的，那么把这个程序添加到空白列表中 <br>　　if(IDYES==MessageBox(0, msgbuff,"WARNING",MB_YESNO|MB_ICONQUESTION|0x00200000L))<br>　　　{a=1; strings[stringcount]=_strdup(name);stringcount++;}<br>　　else a=0;<br>　　// 把响应写入缓冲区中，而由驱动程序之后取回它<br>　　skip:memmove(&amp;outputbuff[4],&amp;a,4);<br>　　//告诉驱动程序继续<br>　　a=0;<br>　　memmove(&amp;outputbuff[0],&amp;a,4);<br>　}<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　这段代码是显然的-我们的线程每10毫秒查询交换缓冲区。如果它发现我们的驱动程序已经把它的请求寄到了该缓冲区中，它就检查被允许在本机上运行的程序列表中的文件的文件名和路径。如果发现匹配，它直接给出一个OK响应。否则，它显示一个消息窗口，询问用户是否允许有问题的程序执行。如果响应是积极的，我们就把有问题的程序添加到允许在本机上运行的软件列表中。最后，我们把用户响应写入缓冲区，也就是说，把它传递到我们的驱动程序。因此，该用户就能完全控制它的PC上的进程的创建-只要我们的程序运行，在没有用户所给予权限的情况下，绝对没有办法来启动该PC上的任何进程。<br><br>　　正如你所见，我们让内核方式代码等待用户反应。这是否是一种聪明的举措呢？为了回答这个问题，你必须问你自己你是否正在堵住任何关键的系统资源-一切都依赖于具体的情况。在我们的情况下，一切发生在IRQLPASSIVE_LEVEL级上，并没有包含对IRPs的处理，并且必须等待用户响应的线程并不十分重要。因此，在我们的情况下，一切工作正常。然而，本例仅为演示之目的而编写。为了实际地使用它，以一个自动启动的服务的方式来重写我们的应用程序是很重要的。在这种情况下，我建议我们解除LocalSystem帐户，并且，在NtCreateSection()被用LocalSystem帐户特权在一个线程的上下文中调用的情况下，可以继续实际的服务实现而不施行任何检查-不管怎么说，LocalSystem帐户仅运行那些在注册表中指定的可执行程序。因此，这样的一种解除不会是与我们的安全相妥协的。<br><br>　　<strong>四、 结论</strong><br><br>　　最后，我必须指出，钩住本机API很明显是现已存在的最强有力的编程技术之一。本文通过一个例子向你展示通过钩住本机API可以实现的能力-正如你所见，我们已设法防止未被授权的程序的执行-这可以通过钩住单一的本机API函数来实现。你可以进一步扩展这个方法，并且获得对硬件设备、文件IO操作、网络流量等等的完全控制。然而，我们现在的解决方案并不是准备为内核模式API调用者所用-一旦内核模式代码被允许直接调用ntoskrnl.exe的输出，则这些调用就不需要经由系统服务发送者进行了。<br><br>　　本文源码在运行Windows XP SP2的若干机器上成功地测试过。尽管我还没在任何另外的环境下面测试它，我相信它应该到处工作正常-不管怎么说，它从未使用任何系统特定的结构。为了运行这个示例，所有你要做的是放置protector.exe和protector.sys到相同的目录下，并且运行protector.exe。直到protector.exe的应用程序窗口被关闭为止；否则，每次你都会被提示你试图运行任何可执行程序。 
<img src ="http://www.cppblog.com/elva/aggbug/46491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-04-08 11:17 <a href="http://www.cppblog.com/elva/archive/2008/04/08/46491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动程序安装-INF</title><link>http://www.cppblog.com/elva/archive/2008/03/17/44672.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 17 Mar 2008 02:00:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2008/03/17/44672.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/44672.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2008/03/17/44672.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/44672.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/44672.html</trackback:ping><description><![CDATA[<p><span>当用户刚插上设备或启动引导（<span>Boot</span>）时，设备是刚刚物理存在于机器上时，总线驱动应自动地，动态的检测，识别硬件的变化。这时，就要有一个识别设备，安装驱动的<span>INF</span>文件。</span></p>
<p><span>所谓文件是指用一个共同的符号名称作为代表，若干个逻辑记录构成的信息集合或目的，形式和内容的表示上彼此相似的一些信息项的集合。简单的说，就是具有一定名称的一组相关数据的集合。</span></p>
<p><span>所谓<span>INF</span>文件，就是以<span>INF</span>为扩展名的文本文件，他控制与驱动安装程序有关的大多数活动。</span></p>
<p><span>因为这个<span>INF</span>文件抽象了设备的上层建筑，含有安装驱动所有的必需的信息，所以它要由驱动开发人员随驱动一起提供，来告诉操作系统那些文件需要复制到用户的硬盘上，应添加或修改哪个注册表等。简单的说，<span>INF</span>文件就是机器的参考文件（<span>Information File</span>）。</span></p>
<p><span>INF</span><span>文本文件与<span>Windows 3</span>。<span>X</span>的<span>INI</span>文件很类似，<span>INF</span>文件分为几节，每节包括一项或几项。每节与安装过程中的某一步相关：比如说，某一节是关于文件拷贝的。某一节是关于如何添加注册表项等等。作为一个开发者，你可以通过任何文本编辑器创建生成<span>INF</span>文件。<span>Microsoft</span>还在<span>DDK</span>中提供了<span>INFEDIT</span>工具，使拥护可以很方便的编辑<span>INF </span>文件（如果实例用<span>INFEDIT</span>，请参阅<span>DDK</span>）。</span></p>
<p><span>INF</span><span>文件可以支持很复杂的安装脚本，但是大多数的开发者只愿意使用处理一些最基本的脚本。一个基本的安装脚本应该包括：</span></p>
<p><span>1</span><span>鉴定硬件设备</span></p>
<p><span>2</span><span>把驱动程序从安装盘上拷贝到系统盘上去</span></p>
<p><span>3</span><span>鉴定硬件设备资源的需求</span></p>
<p><span>4</span><span>当硬件设备被仿真是，就在注册表中加上<span>DevLoader</span>一项</span></p>
<p><span><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195624703625.jpg" border=0></span></p>
<p><span><span></p>
<p><span>INF</span><span>文件通常与磁盘或光盘上的硬件驱动程序一起提供。<span>INF</span>文件的结构和内容由驱动程序创作者决定</span></p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>举例说明</span></p>
<p><span>下面举例说明有关<span>INF</span>的基本特征和内容，以便更好的理解。</span></p>
<p><strong><span>[Version]</span></strong></p>
<p><span>Singnature=$windowsNT$<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span><span>选择版本</span></p>
<p><span>Class=Unknown<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span><span>系统定义用户指定的类名</span></p>
<p><span>Provider=%ABCD% <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>//</span><span>提供商</span></p>
<p><span>DirverVer=11/15/2001<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span></p>
<p><span>CatelogFile[.Ntetc]<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span><span>包含<span>WHQL</span>数字签名的目录说明文件。</span></p>
<p>&nbsp;</p>
<p><strong><span>[Strings]</span></strong></p>
<p><span>ABCD=&#8221;me, the writer&#8221;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span><span>定义宏</span></p>
<p><strong><span>[SourceDisksNames]<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>//</span></strong><span>源代码盘或发行盘的描述，目录和打包文件<strong></strong></span></p>
<p><span>L=&#8221;Ggdriver directory&#8221;&#8230;obj\i386\</span></p>
<p><strong><span>[SourceDisksFiles]<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><span>//</span><span>和打包文件<strong></strong></span></p>
<p><span>Ggdriver.sys=l,obj\i386\some\</span></p>
<p><strong><span>[DestinationDirs]</span></strong><span> //</span><span>复制缺省文件和<span>Filelist</span>节中的文件，</span></p>
<p><span>//</span><span>指定目录和子目录的<span>ID </span>并指定文件的标准位置。</span></p>
<p><strong></strong>&nbsp;</p>
<p><span>Ggdiver.Files.Driver=10,System32\Drivers</span></p>
<p><span>Ggdiver.Files.Driver=10, System32\Drivers</span></p>
<p><strong><span>[Manufacturer]</span></strong><span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>//</span><span>指定生产厂商和<span>models</span>节中相应的名称<strong></strong></span></p>
<p><span>%ABCD%=Ggdriver</span></p>
<p><strong><span>[models]<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><span>//</span><span>最新的硬件<span>ID</span>号先出现</span></p>
<p><span>%USBDevice_V2%=V2Install,USB\VID_ABCD%PID_EFOL&amp;REV_DO02</span></p>
<p><span>%USBDevice_V1%=V2Install,USB\VID_ABCD%PID_EFOL</span></p>
<p><strong><span>[install]</span></strong><span> <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>//</span><span>指向添加的设备接口列表<strong></strong></span></p>
<p><span>Copyfiles=Ggdriver.Files.Driver</span></p>
<p><span>AddReg=Ggdriver.AddReg</span></p>
<p><span>LogConfig=logconfig</span></p>
<p><span>DirverVer=19/10/2001</span></p>
<p><span>ProfileItems=AB\cd</span></p>
<p><strong><span>[filelist]</span></strong></p>
<p><strong><span>[addreg]</span></strong></p>
<p><strong><span>[logconfig]</span></strong></p>
<p><strong><span>[install.AddService]</span></strong></p>
<p><span>ServiceTypy=l</span></p>
<p><span>StartType=start-code</span></p>
<p><span>ErrorControl=error-control-level</span></p>
<p><span>ServiceBinary=path-tc-driver</span></p>
<p><span>INF</span><span>文件是一个文本文件，由不同的节组成，每一个节从括在方括号中的节名称开始，后面是节的内容。这些节也是分层的，其先后顺序与本样例基本保持一致。</span></p>
<p><span>在上面的样例中：</span></p>
<p><span>在<strong><span>[Verson&nbsp;]</span></strong>节中，<strong><span>Signature</span></strong>项只能在<span>$WindowsNT$,$Winfows95$</span>以及<span>$WindowsNT$</span>中选一；</span></p>
<p><strong><span>Provider</span></strong><span>项是<span>INF</span>文件的创造者，通常是设备的生产商；</span></p>
<p><strong><span>Class</span></strong><span>项是系统定义用户指定的类名；</span></p>
<p><strong><span>CatalogFile[.NTetc]</span></strong><span>则是必须包含的驱动程序包的<span>WHQL</span>数字签名的目录说明文件。</span></p>
<p><span>在<strong><span>[Strings ]</span></strong>节中定义代替字符串的宏：<span>&nbsp;</span></span></p>
<p><span>如例中：<span>ABCD=</span>&#8220;<span>me,the writer</span>&#8221;即是说<span>%ABCD%</span>的意思是<span>me,the writer</span>。而在使用时，也用&#8220;<span>me</span>，<span>the writer</span>&#8221;代替<span>ABCD</span>。为了适应不同的语言上下文，可以在<span>String </span>的后面附加（在<span>Winnt</span>。<span>H`</span>中定义的）<span>LangID</span>和<span>SubLangID</span>，形成新的<span>Strings</span>节。<span>LangID</span>和<span>SubLangID</span>都是两位数，它们合作指定某语言上下文。</span></p>
<p><span>如定义一个英国英语（<span>0902</span>）的<span>flour:</span></span></p>
<p><strong><span>[Strings]</span></strong></p>
<p><span>ABC=&#8221;Flor&#8221;</span></p>
<p><strong><span>[Strings.0902]</span></strong></p>
<p><span>ABC=&#8221;Flour&#8221;</span></p>
<p><strong><span>[SourceDisksName]</span></strong><span>与<strong><span>[SourceDisksFiles]</span></strong>节分别是指源代码盘或发行盘的描述，目录和打包文件。如果所有文件都在根目录中，<span>[SourceDisksFiles]</span>节可以是在空的</span></p>
<p><span>在<strong><span>[DestinationDirs]</span></strong>节中，复制缺省文件和<span>Filelist</span>节中的文件，指定目录和子目录的<span>ID </span>并指定文件的标准位置。</span></p>
<p><strong><span>[Manufacture]</span></strong><span>节指定生产厂商和<span>models</span>节中相应的名称；</span></p>
<p><strong><span>[install]</span></strong><span>节则指向添加的设备接口列表，接口键的注册表，其中：</span></p>
<p><span>Copyfiles=filename|filelist</span><span>项，指定要复制的文件或后面列出文件的列表节的名称。</span></p>
<p><span>AddReg=addreg</span><span>项，指定后面遗留设备节的名称。</span></p>
<p><span>LogConfig=logconfig</span><span>项，指定后面遗留设备节的名称。</span></p>
<p><span>ProfileItems</span><span>项，指定添加到计算机界面&#8220;开始&#8221;菜单中的文件名称项。</span></p>
<p><strong><span>[filelist]</span></strong><span>指定要安装的文件列表。</span></p>
<p><strong><span>[addreg]</span></strong><span>节，指定新的键和值。</span></p>
<p><strong><span>[logconfig]</span></strong><span>节，指定遗留设备的<span>I/O</span>地址，<span>IRQ</span>等配置的详细信息。</span></p>
<p><strong><span>[install</span></strong><strong><span>。<span>AddService]</span></span></strong><span>节，只针对<span>Windows2000</span>的驱动程序，指定驱动程序的详细信息。</span></p>
<p>&nbsp;</p>
<p><span>下面我们具体介绍一下<span>INF</span>文件结构。</span></p>
<h1><span>1.1INF</span><span>文件结构</span></h1>
<p><span>一个<span>INF</span>文件是一个被划分为节（<span>Section</span>）的简单的文本文件，每节由方括号（<span>[]</span>）内的标示符表示。某些节名字是必须的，而另一些是驱动程序专用的。每节下面的各项控制某些安装操作，或者连接或列举其它节。</span></p>
<p><span>文件中各节出项的顺序并不重要，因为每节都被命名和链接了。一节内容在遇到另一节或者遇到文件结尾之前继续执行。规定节的唯一的名字是区分大小写的，并且在长度上必须限制在<span>28</span>个字符以内，以保持与<span>Windows 98 </span>的兼容性。节的名字可以包括空格，但是只有在整个名字应用时。允许下划线和点字符。</span></p>
<p><span>节中各项的基本格式如下：</span></p>
<p><span>entry=value[</span><span>，<span>value&#8230;.]</span></span></p>
<p><span>这里的<span>entry</span>是一个指令，关键字或者文件名，而<span>value</span>是应用于<span>entry</span>的属性。</span></p>
<p><span>下图表示了节名字链接。</span></p>
<p><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195624823453.jpg" border=0></p>
<p><span>Entry</span><span>或<span>value</span>名字可以规定为一个字符串记号（<span>string token</span>），它是一个由百分号<span>%</span>包围的替换字节串，一个独立的<span>INF</span>节<span>——[Strings]</span>，给指定的语言<span>ID</span>提供了字符串记号值。</span></p>
<p><span>下面我们看一下<span>INF</span>文件的各个小节及小节的基本内容：（表<span>1</span>，表<span>2</span>）</span></p>
<p><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195628876140.jpg" border=0></p>
<p><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195629233312.jpg" border=0></p>
<p><span>下面我们详细每一节的内容：</span></p>
<h1><span>1.2 Version</span><span>节</span></h1>
<p><span>一个有效的<span>INF</span>文件以一个<span>[Version]</span>节开始，它担当整个<span>INF</span>文件的头部和签名。<span>[Version]</span>节中允许的和要求的项都列在了下表-3</span></p>
<p>&#160;</p>
<p><span></p>
<h1><span><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195628839828.jpg" border=0></span></h1>
<h1><span>1.3 Manufacturers</span><span>节</span></h1>
<p><span>另一个必须的节是<span>[Manufacturers]</span>项。该节中的每个项列出<span>INF</span>文件安装的设备和他们的驱动程序。每个项的格式如下：</span></p>
<p><span>&nbsp;manufacturer=model</span></p>
<p><span>这里的<span>manufacturer</span>列出要被安装的一个或多个硬件型号的制造商在<span>INF</span>文件中的唯一名字。<span>Model</span>值指向另一个<span>INF</span>节名字，进一步列出硬件型号驱动程序安装的方向。</span></p>
<h1><span>1.4 Models</span><span>节</span></h1>
<p><span>对于列在<strong><span>[Manfacturers]</span></strong>节中的每个型号，必须有一个相应的节作为由<span>model</span>指定的节出现。每个<span>model</span>项的形式为：</span></p>
<p><span>device-description=install-section-name</span><span>，<span>hw-id[</span>，<span>compatible-id&#8230;]</span></span></p>
<p><span>这里的<span>device-description</span>表示人可以理解的设备型号列表和一个简单的描述。在一些安装过程中此字符串在一个对话框中提交给用户，因此有必要提供多种语言作为字符串记号。</span></p>
<p><span>&nbsp;install-section-name</span><span>值引用<strong><span>[DDInstall]</span></strong>节，表示值进一步安装的另一个<span>INF</span>节，<span>hw-id</span>值是硬件设备在<span>PNP</span>兼容的总线上声明时返回的<span>PnP</span>标示符。例如。<span>USB \ VID_045E&amp;PID_OOB<span>&nbsp;&nbsp; </span></span>标示<span>USB</span>上的<span>Microsoft HID</span>（<span>Human Input Device</span>）键盘设备。能够增加任意数量的<span>compatlible-id</span>值，表示相同的安装脚本可以用于列表中包含的任何设备。</span></p>
<h1><span>1.5 DDInstall</span><span>节</span></h1>
<p><span>在<span>INF</span>节名字链表的低部附近（但并非最低部）是<strong><span>[DDInstall]</span></strong>节，它从<strong><span>[Models]</span></strong>节中为每个制造商的每个型号规定一个唯一的名字。<strong><span>[DDInstall]</span></strong>节中允许的和要求的项目见下面表4.</span></p>
<p><span></span></p>
<p><span><span></p>
<p><span><img height=435 alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195627531046.jpg" width=736 border=0></span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然在语法上只有<span>AddReg</span>项是必需的，但是<span>CopyFiles</span>项是<strong><span>[DDInstall]</span></strong>节的一个基本指令。它采取如下形式：</span></p>
<p><span>CopyFiles = file &#8211; list &#8211; section [</span><span>，<span>file &#8211; list &#8211; section&#8230;.]</span>或者</span></p>
<p><span>CopyFile = @filename</span></p>
<p><span>前一种形式更加常用，因为它允许一个间接指针指向包含被安装的文件列表的其他节。然而，对于简单的驱动开发程序安装，采取直接文件名方法就行了。在下面两个小节中将对<span>AddReg</span>和<span>CopyFiles</span>指令做进一步解释。</span></p>
<h1><span>1.6 &nbsp;CopyFiles</span><span>节</span></h1>
<p><span>INF</span><span>文件的<strong><span>[CopyFiles]</span></strong>节有一个唯一的名字，并从<strong><span>[DDInstall]</span></strong>节的<strong><span>CopyFiles</span></strong>指令引用它。该节中的每个项采用如下形式：</span></p>
<p><strong><span>destination &#8211; filename[</span></strong><strong><span>，<span>source- filename</span>，<span>temp-filename</span>，<span>flag]</span></span></strong></p>
<p><span>这里的<strong><span>destiantion-filename</span></strong>是最重要复制的目标文件名。如果源文件名不相同，必须规定<strong><span>source &#8211; filename</span></strong>。<span>Temp-filename</span>值不再适用（虽然<span> Windows 98</span>仍然要求），它在系统再次引导之前规定新文件的临时文件名。对于<span>Windows 2000</span>，忽略此值。</span></p>
<p><strong><span>&nbsp;Falg </span></strong><span>值规定对新目标文件的处理，其描述见表<span>5</span>。可以对<span>falg</span>值中的各个为进行&#8220;或&#8221;运算，以使多个操作起作用。几种操作是互斥的（例如，<span>WARN_IF_SKIP</span>和<span>NOSKIP</span>）<span>,</span>有疑问时应当查阅有关文档。</span></p>
<p><span>因为<strong><span>[CopyFiles]</span></strong>节的项的语法没有包含一个可选项来规定源文件的磁盘或路径，必须使用其他<span>INF</span>节——<strong><span>[SourceDisksNames]</span></strong>和<strong><span>[SourceDisksFiles]</span></strong>。然而<strong><span>[CopyFiles]</span></strong>节中各项复制的文件由另一个<span>INF</span>节——<strong><span>[DestiantionDirs]</span></strong>节指定。</span></p>
<p><span><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195625631078.jpg" border=0></span></p>
<p><span></p>
<h1><span>1.7 AddReg</span><span>节</span></h1>
<p><span>一个<span>INF</span>文件的<strong><span>[AddReg]</span></strong>节被唯一命名，并从<strong><span>[DDInstall]</span></strong>节中的<strong><span>AddReg</span></strong>指令引用它。此节的目的是提供增加或者修改目标系统注册表中的项目。本节中每个项目采取如下形式：</span></p>
<p><span>&nbsp;<strong>reg-root[</strong></span><strong><span>，<span>subkey</span>，<span>value- name</span>，<span>flags </span>，<span>value]</span></span></strong></p>
<p><span>这里的<span>reg- root</span>是注册表库（<span>hive</span>）之一的缩写，见表<span>6</span>所列。值表示要被修改的注册表库。<strong><span>Subbkey</span></strong>值表示库底下的键名，在层次结构中子键用反斜线（<span>\</span>）字符隔开。例如，<span>software\W2KdriverBook\Driver\Seting </span>是<span>HKCU</span>或者<span>HKLM</span>库的一个有效子键。</span></p>
<p><img height=252 alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195627853734.jpg" width=738 border=0></p>
<p><span>Value-name</span><span>指定要增加或修改的注册表值。每个注册表键包含一个或多个值，保存不同类型的数据。注册表编辑器（<span>Registy Editor</span>）在右边面板中列出子键的值。值名和值数据同时在该面板中出现，左边面板只列出子键。图<span>3</span>说明了注册表术语之间的关系。</span></p>
<p><span>Flags</span><span>指定数据保存的类型，<span>flages</span>可能的位置见表<span>7</span>所列:</span></p>
<p><span><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195626077765.jpg" border=0></span></p>
<p><span><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195626181078.jpg" border=0></span></p>
<p><span></p>
<h1><span>1.8 &nbsp;SourceDisksNames</span><span>节</span></h1>
<p><span>如果<span>INF</span>文件控制的驱动程序文件的分布跨越多个磁盘（软盘或光盘），则<span>INF</span>文件必须包含一个<strong><span>[SourceDisksNames]</span></strong>节。本节在分布集中为每个磁盘包含一项，项目采取如下形式：</span></p>
<p><span>Diskid=disk &#8211; descript[</span><span>，<span>tagfile</span>，<span>unused</span>，<span>path]</span></span></p>
<p><span>这里的<span>diskid`</span>是分布集内的一个一个唯一的编码。通常，磁盘从<span>1</span>开始编码。<span>Disk &#8211; description </span>标签是一个供人阅读的文本串，可以保证安装过程中拥护提供正确的磁盘，在安装过程继续之前核对<span>tagfile</span>值是否在插入的煤体上。如果<span>tagfile</span>文件不存在，则提示用户插入正确的磁盘。如果<span>tagfile</span>值包含<span>-CAB</span>扩展，则该文件被认为是磁盘上驱动程序源文件的压缩文件集。</span></p>
<p><span>Path</span><span>值是磁盘上驱动程序源文件的相对于根目录的磁盘路径。与<span>tagfile</span>值一样，<span>path</span>是可选的。如果忽略它，则认为根目录是文件的源。</span></p>
<h1><span>1.9 SourceDisksFiles</span><span>节</span></h1>
<p><span>驱动程序<span>INF</span>文件还必须包含一个称为<strong><span>[SourceDisksFiles]</span></strong>的节。此节列出驱动程序安装期间使用的文件名。每个文件对应于本节中的一个项，并采取如下形式：</span></p>
<p><span>Filename = diskid[</span><span>，<span>sbdir</span>，<span>size]</span></span></p>
<p><span>很自然，<span>diskid</span>值在<strong><span>[SourceDisksNames]</span></strong>节中指定了找到<span>filename</span>的一个磁盘，<span>subdir</span>值可选，它指定文件在磁盘上的一个路径。<span>Size</span>值可选，指定文件以字节为单位的未压缩大小。在开始文件复制前，安装进程可以使用此大小确定源文件是否合适目标系统。</span></p>
<h2><span>1 &nbsp;DestinationDirs</span><span>节</span></h2>
<p><span>这是<span>INF</span>文件中必需的节，指定源文件的目标目录。没有这部分内容，安装程序或进程将没有用来拷贝文件的目标目录。<span>[DestinatonDirs]</span>节中的项采取如下形式：</span></p>
<p><span>File &#8211; list &#8211; section = dirid[</span><span>，<span>subdir]</span>或者</span></p>
<p><span>DefaultDestDir = dirid[</span><span>，<span>subdir]</span></span></p>
<p><span>这里<span>file &#8211; list &#8211; section</span>规定了在<strong><span>[CopyFiles]</span></strong>指令中调出来的部分。它规定一个指令拷贝的所有文件安装到指定的目录。对于项目<span>DefaultDestDir</span>，上述规范适用于所有<span>[CopyFiles]</span>指令，否则不会与<span>[DestionationDirs]</span>节中的<span>file- list &#8211; section</span>项关联。</span></p>
<p><span>Dirid</span><span>值根据表<span>8</span>规定了目标的一个列举值。如果提供了值<span>subdir</span>，它指定<span>diid</span>调处的目录下面的一个相对路径。</span></p>
<p></span>&nbsp;</p>
<p><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195626333015.jpg" border=0></p>
<h2><span>2. DDInstall.Services</span><span>节</span></h2>
<p><span>为了真正的使复制的文件成为目标系统上的驱动程序，必须通知服务器管理程序（<span>SCM</span>）。安装在<span>Windows 2000</span>下的每个驱动程序在<span>HKLM\System\Current-ControlSet\Services</span>下的注册表中有一项。<span>ServiceType</span>值为<span>1</span>表示一个内核模式设备驱动程序。<span>StartType</span>指定在引导过程中的什么点上驱动程序装入（<span>3</span>表示按需或手动启动）。在驱动程序装入过程中遇到错误时，<span>ErrorControl</span>值确定发生了什么情况。<span>ServiceBinary</span>值指向驱动程序文件（。<span>SYS</span>文件）的位置，但是，如果二进制值位于<span>%windir%\system32\drivers</span>目录，并且与<span>HKLM\&#8230;\Services</span>下的子键有相同的名字，则可以忽略<span>ServiceBinary</span>值。</span></p>
<p><span>DDInstall.Services</span><span>节项目中包括一个形式如下的项目：</span></p>
<p><span>AddService = ServiceName</span><span>，<span>[flags]</span>，<span>service &#8211; install &#8211; section[</span>，<span>eventlog &#8211; install &#8211; section]</span></span></p>
<p><span>这里的<span>ServiceName</span>表示设备的名字，通常是驱动程序的名字，没有。<span>SYS</span>扩展名。<span>Flags</span>值的描述见表<span>9</span></span></p>
<p><span>Service &#8211; install &#8211; section</span><span>和可选的<span>eventlog- install &#8211; section</span>值调出控制服务值项目（诸如<span>ServiceType</span>和<span>StartType</span>）的新增的<span>INF</span>节名字。</span></p>
<p><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195627101078.jpg" border=0></p>
<h2><span>3. ServiceInstall </span><span>节</span></h2>
<p><span>[ServiceInstall]</span><span>节名字实际上由<span>DDInstall.Services</span>节中每个<span>AddService</span>项唯一规定，它控制把驱动程序安装到服务控制管理程序。<span>[ServiceInstall]</span>节允许的项见表<span>10</span>所列。</span></p>
<p><img alt="" src="http://xly.mentor100.com/kindeditor/attached/200711211195627147343.jpg" border=0></p>
<h2><span>4 .</span><span>验证<span>INF</span>语法</span></h2>
<p><span>DDK</span><span>包含一个基本的工具<span>CHKINF</span>，在<span>DDK</span>的<span>Tools</span>目录中。它依赖于<span>Perl</span>脚本引擎，该引擎可以从<span><a href="http://www.perl.com/">www.perl.com</a></span>上下载。虽然工具没有什么优点，但它在检查标准<span>Microsoft INF</span>文件时能报告许多错误。工具以<span>HTML</span>文件形式输出。</span></p>
<p><span>DDK Tools</span><span>目录还包括一个用语简化<span>INF</span>文件构造的实用程序<span>CENINF</span>。<span>EXE </span>。 必须把该工具区分为基本工具，它对入门者是有用的。</span></p>
<p><span>最后，<span>DDK</span>提供了<span>STAMPINF</span>。<span>EXE</span>这一简单工具，它提供了快速增加或修改<span>INF</span>中版本信息的机制。</span></span></span></span></span></span></span></p>
<img src ="http://www.cppblog.com/elva/aggbug/44672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2008-03-17 10:00 <a href="http://www.cppblog.com/elva/archive/2008/03/17/44672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hook API监视驱动的加载 </title><link>http://www.cppblog.com/elva/archive/2007/12/13/38402.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Thu, 13 Dec 2007 03:37:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/12/13/38402.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/38402.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/12/13/38402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/38402.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/38402.html</trackback:ping><description><![CDATA[<div class=postbody>
<pre>				<span class=comment>;**************************************************************************************************<br>;Author:dge/D哥<br>;Date  :2006.7.20<br>;**************************************************************************************************<br>;f:\masm32\bin\ml /nologo /c /coff HookAPI.asm<br>;C:\&gt;f:\masm32\bin\link /nologo /driver /base:0x10000 /align:32 /out:HookAPI.sys /subsystem:native HookAPI.obj<br></span>
<span class=float>
.386</span>
<span class=operator>
.</span>
<span class=functions>model flat</span>
<span class=operator>,</span>
<span class=functions> stdcall<br>option casemap</span>
<span class=operator>:</span>
<span class=functions>none</span>
<span class=comment>
;**************************************************************************************************
</span>
<span class=type>include</span> f<span class=operator>:\</span>masm32<span class=operator>\</span><span class=type>include</span><span class=operator>\</span>w2k<span class=operator>\</span>ntstatus<span class=operator>.</span><span class=functions>inc</span><span class=type>
include</span> f<span class=operator>:\</span>masm32<span class=operator>\</span><span class=type>include</span><span class=operator>\</span>w2k<span class=operator>\</span>ntddk<span class=operator>.</span><span class=functions>inc</span><span class=type>
include</span> f<span class=operator>:\</span>masm32<span class=operator>\</span><span class=type>include</span><span class=operator>\</span>w2k<span class=operator>\</span>ntoskrnl<span class=operator>.</span><span class=functions>inc</span><span class=type>
includelib</span> f<span class=operator>:\</span>masm32<span class=operator>\</span><span class=functions>lib</span><span class=operator>\</span>w2k<span class=operator>\</span>ntoskrnl<span class=operator>.</span><span class=functions>lib</span><span class=type>
include</span> f<span class=operator>:\</span>masm32<span class=operator>\</span>Macros<span class=operator>\</span>Strings<span class=operator>.</span>mac<span class=comment>
;**************************************************************************************************
</span><span class=operator>.</span><span class=functions>data</span><span class=comment>
;保存地址
</span>dwOldNtLoadDriver<span class=functions>   dd</span><span class=operator>            ?</span>
dwAddr<span class=functions>              dd</span><span class=operator>            ?</span>
dwDriverName        ANSI_STRING<span class=operator>  &lt;?&gt;<br>.</span><span class=keyword>const</span>
CCOUNTED_UNICODE_STRING<span class=string> "\\Device\\devHookApi"</span><span class=operator>,</span> g_usDeviceName<span class=operator>,</span><span class=int> 4</span>
CCOUNTED_UNICODE_STRING<span class=string> "\\??\\slHookApi"</span><span class=operator>,</span> g_usSymbolicLinkName<span class=operator>,</span><span class=int> 4</span>
CCOUNTED_UNICODE_STRING<span class=string> "ZwLoadDriver"</span><span class=operator>,</span> g_usRoutineAddr<span class=operator>,</span><span class=int> 4</span><span class=comment>
;**************************************************************************************************
</span><span class=operator>.</span><span class=functions>code</span><span class=comment>
;让这个函数在NtLoadDriver的调用时被执行以实现监视
</span>NewNtLoadDriver<span class=functions>     proc</span>  lpDriverName<span class=operator>:</span>PUNICODE_STRING<span class=functions>
pushad</span><span class=comment>
;      int 3
;                   invoke DbgPrint, $CTA0("\nEntry into NEW\n")
</span><span class=functions>      invoke</span> RtlUnicodeStringToAnsiString<span class=operator>,</span><span class=functions> addr</span> dwDriverName<span class=operator>,</span> lpDriverName<span class=operator>,</span>TRUE<span class=functions>
invoke</span> DbgPrint<span class=operator>,</span> $CTA0<span class=operator>(</span><span class=string>"\nDriverName: %s.sys\n"</span><span class=operator>),</span> dwDriverName<span class=operator>.</span>Buffer<span class=functions>
popad</span><span class=comment>
;调用原函数
</span><span class=functions>      push</span>   lpDriverName<span class=functions>
call</span>   dwOldNtLoadDriver<span class=functions>
ret</span>
NewNtLoadDriver<span class=functions>     endp</span><span class=comment>
;**************************************************************************************************
</span>HookFunction<span class=functions>        proc<br><br>                    pushad</span><span class=comment>
;      int 3
;      invoke DbgPrint, $CTA0("\nEntry into hoookfunction\n")
;下面是用KeServiceDescriptorTabled导出符号获得数组的基地址，这个数组中包含有NtXXXX函数的入口地址。
</span><span class=functions>      mov</span><span class=registers> eax</span><span class=operator>,</span> KeServiceDescriptorTable<span class=functions>
mov</span><span class=registers> esi</span><span class=operator>, [</span><span class=registers>eax</span><span class=operator>]</span><span class=functions>
mov</span><span class=registers> esi</span><span class=operator>, [</span><span class=registers>esi</span><span class=operator>]</span><span class=comment>
;用MmGetSystemRoutineAddress来获得函数ZwLoadDriver的地址。并从这个函数地址后面的第2个字节中取得服务号。从而
;获得以服务号为下标的数组元素。
</span><span class=functions>             invoke</span> MmGetSystemRoutineAddress<span class=operator>,</span><span class=functions>addr</span> g_usRoutineAddr<span class=functions>
inc</span><span class=registers> eax</span><span class=functions>
movzx</span><span class=registers> ecx</span><span class=operator>,</span><span class=type>byte</span><span class=functions> ptr</span><span class=operator>[</span><span class=registers>eax</span><span class=operator>]</span><span class=functions>
sal</span><span class=registers> ecx</span><span class=operator>,</span><span class=int>2</span><span class=functions><br>      add</span><span class=registers> esi</span><span class=operator>,</span><span class=registers>ecx</span><span class=functions>
mov</span> dwAddr<span class=operator>,</span><span class=registers>esi</span><span class=functions><br>      mov</span><span class=registers> edi</span><span class=operator>,</span><span class=type>dword</span><span class=functions> ptr</span><span class=operator>[</span><span class=registers>esi</span><span class=operator>]</span><span class=comment>
;保存旧的函数地址。
</span><span class=functions>      mov</span> dwOldNtLoadDriver<span class=operator>,</span><span class=registers>edi</span><span class=functions>
mov</span><span class=registers> edi</span><span class=operator>,</span><span class=functions>offset</span> NewNtLoadDriver<span class=comment>
;修改入口地址
</span><span class=functions>      cli<br>      mov</span><span class=type> dword</span><span class=functions> ptr</span><span class=operator>[</span><span class=registers>esi</span><span class=operator>],</span><span class=registers>edi</span><span class=functions>
sti
popad
mov</span><span class=registers> eax</span><span class=operator>,</span> STATUS_SUCCESS<span class=functions>
ret</span>
HookFunction<span class=functions>     endp</span><span class=comment>
;**************************************************************************************************
</span>DispatchCreateClose<span class=functions> proc</span> pDeviceObject<span class=operator>:</span>PDEVICE_OBJECT<span class=operator>,</span> pIrp<span class=operator>:</span>PIRP<span class=functions>
mov</span><span class=registers> eax</span><span class=operator>,</span> pIrp<span class=functions>
assume</span><span class=registers> eax</span><span class=operator>:</span><span class=functions>ptr</span> _IRP<span class=functions>
mov</span><span class=operator> [</span><span class=registers>eax</span><span class=operator>].</span>IoStatus<span class=operator>.</span>Status<span class=operator>,</span> STATUS_SUCCESS<span class=keyword>
and</span><span class=operator> [</span><span class=registers>eax</span><span class=operator>].</span>IoStatus<span class=operator>.</span>Information<span class=operator>,</span><span class=int> 0</span><span class=functions>
assume</span><span class=registers> eax</span><span class=operator>:</span><span class=functions>nothing <br><br>             invoke</span>  IoCompleteRequest<span class=operator>,</span> pIrp<span class=operator>,</span> IO_NO_INCREMENT<span class=functions>
mov</span><span class=registers> eax</span><span class=operator>,</span> STATUS_SUCCESS<span class=functions>
ret</span>
DispatchCreateClose<span class=functions> endp</span><span class=comment>
;**************************************************************************************************
</span>DriverUnload<span class=functions>        proc</span> pDriverObject<span class=operator>:</span>PDRIVER_OBJECT<span class=comment>
;必须保存环境，否则后果很严重。在这个函数中恢复被修改的地址。
</span><span class=functions><br>                   pushad</span><span class=comment>
;             int 3
;                   invoke DbgPrint, $CTA0("\nEntry into DriverUnload \n")
</span><span class=functions>                    mov</span><span class=registers> esi</span><span class=operator>,</span>dwAddr<span class=functions>
mov</span><span class=registers> eax</span><span class=operator>,</span>dwOldNtLoadDriver<span class=functions>
cli
mov</span><span class=type> dword</span><span class=functions> ptr</span><span class=operator>[</span><span class=registers>esi</span><span class=operator>],</span><span class=registers>eax</span><span class=functions>
sti
invoke</span> IoDeleteSymbolicLink<span class=operator>,</span><span class=functions> addr</span> g_usSymbolicLinkName<span class=functions>
mov</span><span class=registers> eax</span><span class=operator>,</span>pDriverObject<span class=functions>
invoke</span> IoDeleteDevice<span class=operator>, (</span>DRIVER_OBJECT<span class=functions> PTR</span><span class=operator> [</span><span class=registers>eax</span><span class=operator>]).</span>DeviceObject<span class=functions><br>             popad<br><br>             ret</span>
DriverUnload<span class=functions> endp</span><span class=comment>
;**************************************************************************************************
</span>DriverEntry<span class=functions>         proc</span> pDriverObject<span class=operator>:</span>PDRIVER_OBJECT<span class=operator>,</span> pusRegistryPath<span class=operator>:</span>PUNICODE_STRING<span class=functions>
local</span> status<span class=operator>:</span>NTSTATUS<span class=functions>
local</span> pDeviceObject<span class=operator>:</span>PDEVICE_OBJECT<span class=comment>
;                   int 3
;             invoke DbgPrint, $CTA0("\nEntry into DriverEntry\n")
</span><span class=functions>             mov</span> status<span class=operator>,</span> STATUS_DEVICE_CONFIGURATION_ERROR<span class=functions>
invoke</span> IoCreateDevice<span class=operator>,</span> pDriverObject<span class=operator>,</span><span class=int> 0</span><span class=operator>,</span><span class=functions> addr</span> g_usDeviceName<span class=operator>,</span> FILE_DEVICE_UNKNOWN<span class=operator>,</span><span class=int> 0</span><span class=operator>,</span> FALSE<span class=operator>,</span><span class=functions> addr</span> pDeviceObject<span class=operator>
.</span><span class=flow>if</span><span class=registers> eax</span><span class=operator> ==</span> STATUS_SUCCESS<span class=functions>
invoke</span> IoCreateSymbolicLink<span class=operator>,</span><span class=functions> addr</span> g_usSymbolicLinkName<span class=operator>,</span><span class=functions> addr</span> g_usDeviceName<span class=operator>
.</span><span class=flow>if</span><span class=registers> eax</span><span class=operator> ==</span> STATUS_SUCCESS<span class=functions>
mov</span><span class=registers> eax</span><span class=operator>,</span> pDriverObject<span class=functions>
assume</span><span class=registers> eax</span><span class=operator>:</span><span class=functions>ptr</span> DRIVER_OBJECT<span class=functions>
mov</span><span class=operator> [</span><span class=registers>eax</span><span class=operator>].</span>DriverUnload<span class=operator>,</span><span class=functions>            offset</span> DriverUnload<span class=functions>
mov</span><span class=operator> [</span><span class=registers>eax</span><span class=operator>].</span>MajorFunction<span class=operator>[</span>IRP_MJ_CREATE<span class=operator>*(</span><span class=keyword>sizeof</span><span class=type> PVOID</span><span class=operator>)],</span><span class=functions>        offset</span> DispatchCreateClose<span class=functions>
mov</span><span class=operator> [</span><span class=registers>eax</span><span class=operator>].</span>MajorFunction<span class=operator>[</span>IRP_MJ_CLOSE<span class=operator>*(</span><span class=keyword>sizeof</span><span class=type> PVOID</span><span class=operator>)],</span><span class=functions>         offset</span> DispatchCreateClose<span class=functions>
assume</span><span class=registers> eax</span><span class=operator>:</span><span class=functions>nothing<br>                                          invoke</span> HookFunction<span class=functions>
mov</span> status<span class=operator>,</span> STATUS_SUCCESS<span class=operator>
.</span><span class=flow>else</span><span class=functions>
invoke</span> IoDeleteDevice<span class=operator>,</span> pDeviceObject<span class=operator>
.</span><span class=functions>endif</span><span class=operator>
.</span><span class=functions>endif<br>             mov</span><span class=registers> eax</span><span class=operator>,</span> status<span class=functions>
ret</span>
DriverEntry<span class=functions>         endp<br><br>end</span> DriverEntry<span class=comment>
;**************************************************************************************************
</span></pre>
</div>
<img src ="http://www.cppblog.com/elva/aggbug/38402.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-12-13 11:37 <a href="http://www.cppblog.com/elva/archive/2007/12/13/38402.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件过滤驱动开发辅助工具集</title><link>http://www.cppblog.com/elva/archive/2007/07/31/29080.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Tue, 31 Jul 2007 07:20:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/07/31/29080.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/29080.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/07/31/29080.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/29080.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/29080.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2007/07/31/29080.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/29080.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-07-31 15:20 <a href="http://www.cppblog.com/elva/archive/2007/07/31/29080.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>本地目录的只读控制（禁止写、删除、新建））</title><link>http://www.cppblog.com/elva/archive/2007/05/07/23590.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 07 May 2007 15:54:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/05/07/23590.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/23590.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/05/07/23590.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/23590.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/23590.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2007/05/07/23590.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/23590.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-05-07 23:54 <a href="http://www.cppblog.com/elva/archive/2007/05/07/23590.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件加密标识 －隐藏文件头的黑客代码</title><link>http://www.cppblog.com/elva/archive/2007/05/07/23589.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 07 May 2007 15:51:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/05/07/23589.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/23589.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/05/07/23589.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/23589.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/23589.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2007/05/07/23589.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/23589.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-05-07 23:51 <a href="http://www.cppblog.com/elva/archive/2007/05/07/23589.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows 文件过滤驱动经验总结</title><link>http://www.cppblog.com/elva/archive/2007/05/07/23588.html</link><dc:creator>叶子</dc:creator><author>叶子</author><pubDate>Mon, 07 May 2007 15:48:00 GMT</pubDate><guid>http://www.cppblog.com/elva/archive/2007/05/07/23588.html</guid><wfw:comment>http://www.cppblog.com/elva/comments/23588.html</wfw:comment><comments>http://www.cppblog.com/elva/archive/2007/05/07/23588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/elva/comments/commentRss/23588.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/elva/services/trackbacks/23588.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/elva/archive/2007/05/07/23588.html'>阅读全文</a><img src ="http://www.cppblog.com/elva/aggbug/23588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/elva/" target="_blank">叶子</a> 2007-05-07 23:48 <a href="http://www.cppblog.com/elva/archive/2007/05/07/23588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>