软件调试的变革

新的理念,新的工具

读书笔记_windows下的验证机制

常见的测试手段有以下几种:

  黑盒测试

  白盒测试

  内建自检(BIST,Built-InSelf-Test),是指在软件代码内部构建一些测试功能,这些功能可以在某些情况下执行,或者被自动测试工具所调用以发现问题。

  压力测试(Stresstesting),用于测试目标程序在高负载和低资源情况下的工作情况。

Windows下的验证机制能够模拟极端和苛刻的运行环境,以便让错误更容易暴露出来。

Windows下的验证机制包含驱动程序验证器和应用程序验证器

先来看驱动程序验证器(Driver Verifier),它主要用于验证各种设备驱动程序和内核模块。驱动验证器主要是在内核文件(NTOSKERNL.exe)中一系列内核函数和全局变量,其名字中大多是包含Verifier字样,或者是以Vi和Vf开头。例如用于验证内存池的nt!VerifierFreePool,用于验证降低IRQL操作的nt!VerifierKeLowerIrql.

   (简单介绍一下IRQL)

  IRQL ( Interrupt Request level) 中断请求级别,用来划分windows下中断请求的优先级。常用的IRQL级别有:

  PASSIVE_LEVEL: IRQL最低级别,没有被屏蔽的中断,在这个级别上,线程执行用户模式,可以访问分页内存

   APC_LEVEL: 在这个级别上,只有APC级别的中断被屏蔽,可以访问分页内存。当有APC发生时,处理器提升到APC级别,这样,就屏蔽掉其它APC,为了和APC执行一些同步,驱动程序可以手动提升到这个级别。比如,如果提升到这个级别,APC就不能调用。在这个级别,APC被禁止了,导致禁止一些I/O完成APC,所以有一些API不能调用。

   DISPATCH_LEVEL: 这个级别,DPC 和更低的中断被屏蔽,不能访问分页内存,所有的被访问的内存不能分页。因为只能处理非分页内存,所以在这个级别,能够访问的Api大大减少。

   DIRQL: 一般的,更高级的驱动在这个级别上不处理IRQL,但是几乎所有的中断被屏蔽,这实际上是IRQL的一个范围,这是一个决定某个驱动有更高的优先级的方法。

  驱动验证器的设计原理:

     驱动验证器的基本设计思想是在驱动程序调用设备驱动接口(DDI)函数时,对驱动程序执行各种检查,看是否符合系统定义的设计需求。

    Windows实际上采用的是通过修改被验证驱动程序的输入地址表(Import Address Table, 简称IAT)来挂接(HOOK)驱动程序的DDI调用,也就是之间我的博客中介绍的IAT Hook方法。实现的方法是系统将被验证驱动程序IAT表中的DDI函数地址替换为验证函数的地址。所以当这个驱动程序调用DDI函数时,会调用对应的验证函数。

     验证函数的作用是:

1.      更新计数器,或者全局变量

2.      检测调用参数,或者做其他检查,如果发现异常情况,就会调用KeBugCheckEx函数,然后通过蓝屏机制来报告验证失败

3.      没有发现问题,就会调用原来的函数。

再看一下验证函数的执行过程:

1.  初始化过程:内存管理器的初始化函数MmInitSystem来调用驱动验证器的初始化函数,来初始化驱动验证器,它的工作是创建并初始化一个用来存放被驱动验证驱动程序信息的链表,windows使用全局变量MiSuspectDriverList来记录这个链表。在可疑驱动链表的每个节点都是一个MI_VERIFIER_DRIVER_ENTRY结构,用来记录一个被验证的驱动程序。

2.  挂接验证函数过程

当系统加载一个内核模块时,会调用MiApplyDriverVerifier函数,这个函数的任务就是查询要加载的模块是否在可疑驱动列表中,如果在,则表示这是一个被验证的驱动,并调用MiEnableVerifier函数,对它的IAT表进行修改。

   对于OS Loader(NTLDR)加载的模块,当驱动验证器初始化时(阶段0初始化),驱动验证器的MiInitialzeVerifyComponents函数会遍历所有已经加载的模块,并以此对其调用MiApplyDriverVerifier。对于以后加载的驱动程序,内存管理器的工作函数(MiLoadSystemImage)会调用MiApplyDriverVerifier以给驱动验证器以检查机会。在挂接验证函数后,一旦调用该内核函数,它的验证函数就会首先被执行。

3.  验证过程

Windows2000引入的驱动验证器包含了一些基本的验证项目

        自动检查:主要是判断是否在合适的IRQL级别使用内存,是否有不恰当的切换栈,是否释放包含活动计时器的内存池,是否在合适的IRQL级别获取和释放自旋锁,当驱动卸载后系统也会检测是否已经释放了所有资源。

        特殊内存池,从特殊的内存池来为驱动程序分配内存。系统对这个内存池具有增强的监视功能,能够发现上溢(overrun),下溢(underrun)和释放后又访问等错误情况。

        强制的IRQL检查,强制让驱动程序使用的分页内存失效,并监视驱动程序是否在错误的IRQL级别访问分页内存或持有自旋锁。

        低资源模拟,对驱动程序的内存分配请求或其他资源请求,随即返回失败。

        内存池追踪(Pool Tracking),记录驱动程序分配的内存,释放时看其是否全部释放。

        I/O验证,从特殊内存池分配IRP(I/O Request Packet),并监视驱动程序I/O的处理。

        Windows XP引入了一些新的验证项目

        死锁探测,增强的I/O验证,SCSI验证

         Windows Server 2003

         IRP记录(IRP Logging)

          Windows Vista引入了

         Driver Hang Detection, Completion Routine, Cancellation Routine

         安全检查

         强制I/O请求等待解决

         零散检查

4.  启动驱动那个验证

在运行对话框中输入Verifier,点击OK可以进入图形界面。Windows XP版本为向导模式。也可以使用命令行模式。界面如下所示:


启动驱动验证后,需要重新启动系统,设置才会生效,因为系统只有在启动期间才会初始化可疑驱动链表。Windows Vista对驱动验证器做了增强,可以不重启便可以使验证生效。Windows 7 没有验证过,也应当如此吧。

     每个驱动程序的信息会记录到可疑链表中这个驱动程序对应的MI_VERIFIER_DRIVER_ENTRY结构中,此外,全局信息会被记录到全局变量MmVerifierData中,可以使用WinDBG观察这些值。WinDBG的工具包中叶设计了专门的扩展命令,!Verifier,具体可以查看winDBG的帮助文档。

 

应用程序验证器

    应用程序验证器与驱动程序验证器类似,也是使用IAT HOOK的方式,主要验证它是否符合Windows SDK所定义的设计规范。应用验证器(APP Verifier)包含在应用验证工具包中,可以从windows XP的安装光盘或者微软网站得到这个工具包。具体以后会详细描述。

 

阅读更多
个人分类: 系统安全
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭