zoukankan      html  css  js  c++  java
  • Win8驱动的兼容性问题

    引用注明>> 【作者:张佩】【原文:www.yiiyee.cn/blog

    最近我发现为Win8开发的驱动程序,有些能安装在Win7上(包括更早系统),有些则不能。那些不能安装的情况很可怕:一旦安装并加载驱动,系统就会立刻蓝屏。针对这个问题,做了一番调查研究。发现了一个简单的规律:

    如果开发时使用的是WDM驱动框架,则存在此问题;如果使用KMDF驱动框架,则正常。

    这是为什么呢?一起来看看吧。

    VS2012集成开发环境

    Visual Studio 2012(简称VS2012)中包含了Windows驱动程序编译器,使得Windows驱动也可以在Visual Studio的集成开发环境中进行开发了。安装VS2012后,再安装Win8 WDK,打开VS2012会发现多了两种新的“平台工具集”,支持Windows内核和用户驱动程序的编译。如下图所示:

    toolset

    新建的内核驱动项目,会自动选择合适的工具集:WindowsKernelModeDriver8.0。更改工作集,会影响相关的工程项目设置,比如包含目录的查找路径等。所以,如果把驱动项目的工作集改成用户程序相关的话,编译器会报很多找不到头文件的错误,比如找不到<ntddk.h>。

    targetOs

    和以前的控制台编译环境类似,在IDE环境中,我们也可以选择不同的目标系统:操作系统,硬件平台。通过工具栏上的列表框进行选择。如下图所示:

    我们可以通过工程向导来产生一个WDM内核驱动项目,这里将项目名称设为Test。

    Security Cookie导致的不兼容

    编译器默认开启/GS编译选项,用来保护内核栈的完整性。编译器会在程序开始的地方,保存一个cookie值到栈上;在程序退出时再检查这个cookie值是否被破坏,如果被破坏,说明栈溢出,表明系统遭到了破坏从而需要蓝屏保护。

    GS是一种被普遍运用的保护机制。开启了GS选项后,编译器会链接一个GS相关的库文件来实现GS功能,当目标系统为Win7时库文件是BufferOverflowK.lib,当目标系统为Win8+时库文件是BufferOverflowFastFailK.lib。链接器是如何实现栈保护的呢?它先在驱动加载的时候,也就是GsDriverEntry函数内初始化cookie。然后在每个驱动函数的开始和结束的地方,添加cookie检查的代码。

    链接器为了对cookie进行初始化,会为驱动程序重新生成一个名为GsDriverEntry的入口函数,初始化Cookie后再调用驱动程序自己的DriverEntry入口函数。下面是一个典型的GsDriverEntry的实现:

    Test!GsDriverEntry:
    82ea403e 8bff            mov     edi,edi
    82ea4040 55              push    ebp
    82ea4041 8bec            mov     ebp,esp
    82ea4043 e8bdffffff      call    Test!__security_init_cookie// 初始化cookie
    82ea4048 5d              pop     ebp
    82ea4049 e9b8fff7ff      jmp     Test!DriverEntry (82e24006)//调用DriverEntry
    82ea404e cc              int     3

    下面是Win7版本security_init_cookie函数的逻辑:

    test!__security_init_cookie:
    82eb3005 a10050e382      mov     eax,dword ptr [test!__security_cookie (82e35000)] ds:0023:82e35000=00300083
    82eb300a b94ee640bb      mov     ecx,0BB40E64Eh
    82eb300f 85c0            test    eax,eax
    82eb3011 7404            je      test!__security_init_cookie+0x12 (82eb3017) // 判断是否等于0
    82eb3013 3bc1            cmp     eax,ecx                                     // 判断是否等于0BB40E64Eh
    82eb3015 751a            jne     test!__security_init_cookie+0x2c (82eb3031)
    82eb3017 a13040e382      mov     eax,dword ptr [test!KeTickCount (82e34030)] // 获取当前系统时间
    82eb301c 8b00            mov     eax,dword ptr [eax]
    82eb301e 350050e382      xor     eax,offset test!__security_cookie (82e35000)
    82eb3023 a30050e382      mov     dword ptr [test!__security_cookie (82e35000)],eax
    82eb3028 7507            jne     test!__security_init_cookie+0x2c (82eb3031)
    82eb302a 8bc1            mov     eax,ecx
    82eb302c a30050e382      mov     dword ptr [test!__security_cookie (82e35000)],eax // 生成新cookie值
    
    // 返回
    82eb3031 f7d0            not     eax
    82eb3033 a30450e382      mov     dword ptr [test!__security_cookie_complement (82e35004)],eax
    82eb3038 c3              ret

    这段逻辑先检查security_cookie的当前值,如果不等于0且不等于0xBB40E64E,就立即退出;否则根据当前的系统时间,产生一个随机的cookie值。这里的值0xBB40E64E是个特征值,可能是系统默认生成的。大部分的镜像在加载的时候,其cookie都会被初始化成这个特征值。

    当目标OS为Win8时,编译器默认链接BufferOverflowFastFailK.lib文件,它使用新的Cookie算法。正是这个新算法导致了不兼容性。看看Win8中security_init_cookie函数的逻辑,它硬是和0xBB40E64E较上了劲:

    mov     eax, __security_cookie
    test    eax, eax
    jz      short loc_404029
    cmp     eax, 0BB40E64Eh // 如果等于0BB40E64Eh,跳到下面产生0x29中断,产生蓝屏
    jz      short loc_404029
    not     eax
    mov     __security_cookie_complement, eax 
    retn
    
    loc_404029:                             ; CODE XREF:
    push    6
    pop     ecx
    int     29h               // 蓝屏

    它判断当前的cookie值是否等于特征值0xBB40E64E,如果相等,立刻蓝屏。神奇的是,在 Win7及以前的OS上,大部分的驱动程序的cookie值都会被加载器初始化为0xBB40E64E。而在Win8+系统上则永远不会这样。这就是为什么能在Win8+正常运行的驱动,一放到Win7上就蓝屏的原因。

    WDM和KMDF的区别

    那为什么使用KMDF编译的驱动,又没有问题呢?原因很简单,KMDF框架链接的静态库文件还是BufferOverflowK.lib。不保证KMDF以后的版本不会链接新库文件的可能。

    如何避免

    虽然KMDF兼容性良好,但很多情况下,还是会用WDM框架编写驱动,而且还有很多小端口驱动也可能存在类似问题。如何避免呢。有三种简单的方法:

    其一是为Win7及以前系统和Win8+系统产生不同的镜像文件。这也是比较推荐的方法。

    其二是在Win8+系统上安装为Win7系统编译的驱动程序。经过测试,大多数为Win7编译的驱动程序,都能正常运行在Win8和Win blue系统上。但不保证更新的Windows系统出来后,这种向前兼容性仍然有效。

    其三是干脆关闭GS编译选项。但这样就缺少了栈保护,不推荐。

    最后介绍一种MSDN中介绍的比较高级的修改编译选项的办法,可以让编译器在为Win8+目标系统编译驱动程序时,仍选择旧版本的栈保护库文件BufferOverflowK.lib:

    1. 手动编译,手动设定KernelBufferOverflowLib的路径:
    msbuild /p:KernelBufferOverflowLib="C:Program Files (x86)Windows Kits8.1Libwin8kmx64BufferOverflowK.lib" /p:platform=x64 /p:Configuration="Win8 Release" myDriver.sln
    1. 用记事本软件打开驱动项目的工程文件,并在合适的地方添加下面的属性:
    <KernelBufferOverflowLib>$(DDK_LIB_PATH)BufferOverflowK.lib<KernelBufferOverflowLib>

     

  • 相关阅读:
    PAT 1006 Sign In and Sign Out
    PAT 1004. Counting Leaves
    JavaEE开发环境安装
    NoSql数据库探讨
    maven的配置
    VMWARE 下使用 32位 Ubuntu Linux ,不能给它分配超过3.5G 内存?
    XCODE 4.3 WITH NO GCC?
    在苹果虚拟机上跑 ROR —— Ruby on Rails On Vmware OSX 10.7.3
    推荐一首让人疯狂的好歌《Pumped Up Kicks》。好吧,顺便测下博客园可以写点无关技术的帖子吗?
    RUBY元编程学习之”编写你的第一种领域专属语言“
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3509096.html
Copyright © 2011-2022 走看看