1.1 下载和使用WDK
1.1.1 下载安装WDK
就像应用程序使用开发包SDK一样,内核编程使用“Windows Driver Kit”,简称WDK。WDK已经自带所有需要的头文件、库、C/C++语言及汇编语言的编译器与连接器,所以完全可以在不安装Visual Studio的情况下进行编程。只是工程管理会不太方便,读者可以使用记事本或者自己喜欢的其他文本编辑器进行编程。习惯使用Visual Studio的读者会感觉这很酷,因为只有传说中的骨灰级程序员才使用记事本编程。
建议读者下载一个能显示行号的文本编辑器。以便出现编译错误时能迅速找到错误。Linux爱好者当然可以直接用vim。
有些读者可能听说过DDK或者IFSDDK,但是那已经是历史了,请遗忘它。同时下面的描述也可能成为历史,所以请读者进入主页后应该随机应变。
首先请打开网页:
https://connect.microsoft.com/default.aspx
这个网页必须先登录。登录拦住了不少访客,有些访问者会以为是收费注册的,其实使用Windows Live账号就可以登录(即用MSN账号登录)。如果没有MSN账号,可以去免费注册一个。
有了Live账号之后,还必须用这个账号向Connect注册,才能下载WDK。用Live账号登录之后,下面出现“立即注册Connect!”链接。
注册很简单,只要填写名字、地区和邮箱就可以了。虽然要填写邮箱,但是笔者并没有去打开发送到邮箱中的文件,这个ID就直接可以下载了。笔者不确定是否真的如此,请读者自己尝试一下。
登录之后出现一个“配置控制面板”页面,但是笔者没有使用它,单击上面的“主页”链接,回到主页,能看见显示自己已经登录了。大致画面如图1-1所示。
图1-1 connect.microsoft.com的主页页面
请单击图中用圈圈住的“查看所有站点”。
下面就比较简单了,右边会显示类别,在类别中请选择“开发人员工具”。选择之后左边就有“Windows Driver Kit”可以下载,请按网页的提示逐步下载即可。这个开发包非常大,下载之后有几GB的内容。(注:最新版本的WDK已经缩减,只有几百兆了。)下载WDK之前请先根据此时页面的提示下载并安装FTM(File Transfer Manager),可以大大加快下载速度。
安装过程没有需要特别注意的地方,只有两点:
(1)安装到一个简单一点的路径,避免在特殊情况下需要配置路径时麻烦,比如C:\WinDDK。尤其要避免在路径上有空格,否则可能出现编译问题。
(2)一定要选择“完全安装”,否则可能错过一些代码例子。
1.1.2 编写第一个C文件
现在请打开记事本(或者读者喜欢的任何工具)来创建一个文件,我们把这个文件命名为first.c,以表示这是我们编写的第一个内核编程文件。在进行内核编程时,读者必须打开WDK的帮助。在WDK安装之后,单击“开始”菜单→“所有程序”,会发现增加了“Windows Driver Kits”和“Windows Driver Kits Documentation”两个子菜单。(注:最新版本这两个菜单已经合并为一个。)
选择“Windows Driver Kits Documentation”下面的子菜单来打开帮助。在使用任何一个函数之前,请在帮助里查询这个函数是否存在、使用的环境要求及输入/输出。
因为这不是应用程序编程,所以所有的Win32 API函数都不能使用;部分C Runtime函数也不能使用,但是文档中说明的函数则都可以使用。本书将在文档中有说明的且在内核下调用的System Routine称为内核API函数,以便和Win32 API函数区分。
我们编写first.c内容如下:
/// /// @file first.c /// @author crazy_chu /// @date2008-11-1 /// #include <ntddk.h> // 提供一个Unload函数只是为了让这个程序能动态卸载,方便调试 VOID DriverUnload(PDRIVER_OBJECT driver) { // 但是实际上我们什么都不做,只打印一句话 DbgPrint("first: Our driver is unloading…\r\n"); } // DriverEntry,入口函数。相当于main。 NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) { // 这是内核模块的入口,可以在这里写入我们想写的东西 // 笔者在这里打印一句话。因为“Hello,world”常常被高手耻笑,所以 // 打印一点别的 DbgPrint("first: Hello, my salary!"); // 设置一个卸载函数,便于这个函数退出 driver->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
上面的DriverEntry是每个内核模块的入口,在加载这个模块时被系统进程System调用一次。在其中我们设置了DriverUnload的函数指针,这样这个模块可以被动态地卸载(这将方便我们调试程序);如果没有设置DriverUnload函数指针,则一个内核模块一旦被加载就不能卸载了。
现在请先建立新目录first,然后把first.c文件保存在此目录下,下面我们就介绍编译的方法。
1.1.3 编译一个工程
前面已经建立了工程first,虽然这个工程只有一个first.c文件作为代码文件。现在必须在这个目录下增加两个文件,以便WDK的build工具可以build它。其中一个文件的名字必须为makefile,这个文件的内容很无聊,永远也不需要改动,内容如下:
!IF 0 Copyright (C) Microsoft Corporation, 1999-2002 Module Name: makefile. Notes: DO NOT EDIT THIS FILE!!! Edit.\sources.if you want to add a new source file to this component. This file merely indirects to the real make file that is shared by all the components of Windows NT (DDK) !ENDIF !INCLUDE $(NTMAKEENV)\makefile.def
如果读者不想自己写这个文件,那么请到WDK的src目录下随便寻找一个例子,然后拷贝一个出来。大部分例子的makefile都和这个一样。
另外,还需要一个名字为SOURCES的文件,这个文件的内容关系到这个模块要编译哪些文件,以及编译出来的.sys文件的名字。举例内容如下:
TARGETNAME=first TARGETTYPE=DRIVER TARGETPATH=obj SOURCES=first.c
其中TARGETNAME表示名字,编译出来之后,模块的名字为first.sys;SOURCES表示要编译的.c文件(对于初学者,必须提醒一点,不要加入.h文件,因为.h是被包含在.c文件中编译的),如果.c文件有多个,请用空格分隔。
下面请从“开始”菜单中打开WDK的build环境配置,如图1-2所示。
图1-2 从开始菜单中打开WDK的build环境配置
从“开始”菜单中选择“所有程序”,然后选择“Windows Driver Kits”→WDK的版本(这里“WDK 600118001”)→“Build Enviroments”→“Windows XP”→“Launch Windows XP x86 Checked Build Enviroment”。
出现一个控制台,这个控制台已经配置好编译环境。现在输入cd命令,进入我们先前建立的first目录;进入之后,输入build命令。笔者这里编译的结果如图1-3所示。
图1-3 first编译的结果
现在编译结束,first.sys出现在\first\objchk_wxp_x86\i386下。这个文件并不像普通exe文件一样可以直接双击执行,它需要一个安装工具进行安装。下面讲解如何安装并运行它。