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

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

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

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

VS2012集成开发环境

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

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

和以前的控制台编译环境类似,在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 Kits\8.1\Lib\win8\km\x64\BufferOverflowK.lib" /p:platform=x64 /p:Configuration="Win8 Release" myDriver.sln
  1. 用记事本软件打开驱动项目的工程文件,并在合适的地方添加下面的属性:
<KernelBufferOverflowLib>$(DDK_LIB_PATH)\BufferOverflowK.lib<KernelBufferOverflowLib>

Win8驱动的兼容性问题的更多相关文章

  1. Win8驱动测试模式

    打开驱动测试模式(保存成bat文件,双击执行) bcdedit /set testsigning on pause 执行完成后,看见提示操作成功的提示,之后我们重启一下,再次进入系统,在桌面的右下角会 ...

  2. 解决Win8.1 IE11兼容性问题的方法

    装了64位win8.1企业版,IE11出现了一些兼容性问题,如个别网银网页兼容问题,还有office.迅雷.adobe reader.旋风等等插件不兼容不能加载的问题. 折腾了一天总算全部解决了,主要 ...

  3. USB转串口WIN8驱动安装

    http://jingyan.baidu.com/article/11c17a2c0bb606f446e39da0.html  //查看百度经验 http://jingyan.baidu.com/ar ...

  4. 原装win8系统电脑崩溃问题解决

    原装win8系统电脑崩溃问题解决 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:之所以撰写本篇关于win8原装系统电脑崩溃的博文,一是要吐槽一下原装w ...

  5. [连载]《C#通讯(串口和网络)框架的设计与实现》-3.设备驱动的设计

    目       录 第三章           设备驱动的设计... 2 3.1           初始化设备... 4 3.2           运行设备接口设计... 4 3.3        ...

  6. win8 中使用第三方无线网卡出现无线连接受限解决办法

    无线路由  无线网络模式基本设置 模式改为 11bg mixed , 然后在 win8 的设备管理器中找到无线路由 不知道 win8 有些地方兼容性做的不是很到位,我的 xp不做任何配置可以正常使用.

  7. win8安装matlab7.0

    win8和win7下安装matlab7.0要注意许多地方,其实安装最新版一般都是没有问题的. 不过最新版太大,校园网下载太难,所以还是用7.0 基本上在百度经验上已经包括了大部分的注意事项了,可以参考 ...

  8. windows资源管理器多标签打开 windows文件夹多标签浏览 浏览器tab页面一样浏览文件夹 clover win8 win10 报错 无响应问题怎么解决 clover卡死 clover怎么换皮肤

    大家都知道,我们打开一堆文件夹的时候,是什么样子 “厚厚的一叠”图标堆叠在一起的,非常的不方便 那么,是不是可以像浏览器一样的tab页面展示呢? 答案是可以的 安装好就是这样子的 是不是方便漂亮了很多 ...

  9. ImageMagick: win7 | win8 & uac (用户帐户控制) 注册表的一些事

    现在用win7,win8的人越来越多了, 程序在一些 win 7, win8 上运行会遇到一些之前没想过的兼容性问题. 比如 64位系统运行32位程序时的注册表重定向,还有因为 uac (用户帐户控制 ...

随机推荐

  1. python之函数联系

    ----------------------作业一 # 有两个列表,分别存放来老男孩报名学习linux和python课程的学生名字# linux=['钢弹','小壁虎','小虎比','alex','w ...

  2. python之迭代器篇

    一.迭代器 只要对象本身有_iter_()_方法,那它就是可迭代的 执行__iter__就会生成迭代器 迭代器有__next__用于获取值 __next__超出界限了会报StopIteration异常 ...

  3. Myeclispe 代码自动补全

    1.Myeclispe—>Preference 2.Java->Editor->Content Assist 3.Auto activation for java 补全(.abcde ...

  4. 【分块】教主的魔法 @洛谷P2801/upcexam3138

    时间限制: 1 Sec 内存限制: 128 MB 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列, ...

  5. Nanopi2基本使用

    1.首先刷系统,把TF卡放到读卡器中,根据官网教程(http://www.arm9.net/nanopi-m2.asp)下载固件,并烧写.   2.硬件连接:把TF卡插到Nanopi2的boot卡槽, ...

  6. 2012服务器在IIS部署的SLL(https)网址谷歌浏览器无法访问的问题解决

    服务器环境:Windows Server 2012,IIS8. 当绑定了https,使用IE和Firefox浏览器能够正常访问,但是使用谷歌浏览器会出现net::ERR_CONNECTION_ABOR ...

  7. Android编码学习之Adapter

    1. Apter的作用 Adapter是将数据绑定到UI界面上的桥接类.Adapter负责创建显示每个项目的子View和提供对下层数据的访问.Adapter的作用就是将要在列表内显示的数据和列表本身结 ...

  8. Guava Preconditions 工具参数前置校验

    guava 提供 Preconditions  作为代码校验的工具类,用来简化开发中对代码的校验或预处理,在逻辑开始前进行合理性校验,避免参数传入过深导致的数据错误. 并且能够在不符合校验条件的地方, ...

  9. alpine-bash镜像制作

    alpine轻量级基于busybox的发行版,特别适合基于docker的base images. 特点: small.simple.secure 官方地址: https://alpinelinux.o ...

  10. Linux内核剖析(二)Linux内核绪论

    什么是内核 内核是操作系统最基本的部分.它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并且内核决定一个程序在什么时候对某部分硬件操作多长时间.内核的分类可分为单内核和双内 ...