win7(X64)+wdk7驱动环境搭建

我们知道,编译驱动程序主要是通过两种方案:第一种是通过WinDDK提供的build命令+source文件进行编译;另外一种是通过VC的IDE进行编译。

微软推荐开发者使用第一种,即利用WinDDK提供的编译命令进行编译,但是,本质上,两种方法到最后都是调用cl.exe和link.exe进行编译,区别只是两种方法设置参数、环境变量的方式不同而已。

1、准备

       wdk7下载地址:    https://www.microsoft.com/en-us/download/details.aspx?id=11800

    vmware12: (我选择vmware12是因为 其对win7的支持,有些版本对操作系统的是有要求的) 

       win7:   https://msdn.itellyou.cn/        打开后,选择左侧的操作系统,找到合适你的需求版本下载(下载推荐选择  迅雷,下载链接是  edk2 哦)

       DriverMonitor:  (Google一下,自行下载)。 主要用来加载和卸载驱动。

       DebugView:      https://docs.microsoft.com/zh-cn/sysinternals/downloads/debugview   (查看内核输出)

       64signer: 驱动签名工具。  Google一下, 自行下载

2、环境搭建

     A、安装 vmware12 , 再 创建 win7 X64的虚拟机。 (不会? 那就 Google一下) 

     B、安装win7 操作系统, 并激活。 

     C、安装 vmware install tool (  不会? 那就 Google 一下)

3、安装 wdk

     下载wdk后,使用 band  或者其他的解压缩工具 解压, 安装即可。(傻瓜式安装 , 下一步,下一步。。。。。) 

    安装结束后: 安装目录大概是这样的,

4、编写一个自己的第一个驱动程序

       特别说明, 我使用的是X64    编译。

        我再C盘根目录创建了一个文件夹,名为demo, 里面准备了下面的文件.

        参考的代码内容如下:

复制代码

#ifdef __cplusplus
extern "C"
{
#endif
#include <wdm.h>
#ifdef __cplusplus
}
#endif 

typedef struct _DEVICE_EXTENSION
{
    PDEVICE_OBJECT fdo;
    PDEVICE_OBJECT NextStackDevice;
    UNICODE_STRING ustrDeviceName;    // 设备名
    UNICODE_STRING ustrSymLinkName;    // 符号链接名
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")

#define arraysize(p) (sizeof(p)/sizeof((p)[0]))

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
                           IN PDEVICE_OBJECT PhysicalDeviceObject);
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
                        IN PIRP Irp);
NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo,
                                 IN PIRP Irp);
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject);

extern "C"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
                     IN PUNICODE_STRING RegistryPath);

#include "HelloWDM.h"

/************************************************************************
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
      pDriverObject:从I/O管理器中传进来的驱动对象
      pRegistryPath:驱动程序在注册表的中的路径
* 返回 值:返回初始化驱动状态
*************************************************************************/
#pragma INITCODE 
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
                                IN PUNICODE_STRING pRegistryPath)
{
    KdPrint(("Enter DriverEntry\n"));

    pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
    pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = 
    pDriverObject->MajorFunction[IRP_MJ_CREATE] = 
    pDriverObject->MajorFunction[IRP_MJ_READ] = 
    pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
    pDriverObject->DriverUnload = HelloWDMUnload;

    KdPrint(("Leave DriverEntry\n"));
    return STATUS_SUCCESS;
}

/************************************************************************
* 函数名称:HelloWDMAddDevice
* 功能描述:添加新设备
* 参数列表:
      DriverObject:从I/O管理器中传进来的驱动对象
      PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象
* 返回 值:返回添加新设备状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
                           IN PDEVICE_OBJECT PhysicalDeviceObject)
//DriverObject就是指向本驱动程序的一个对象,是由PNP管理器传递进来的。
//PhysicalDeviceObject是PNP管理器传递进来的底层驱动设备对象,这个东西在NT驱动中是没有的。通常称之为PDO,确切的说是由总线驱动创建的。

    PAGED_CODE();
    KdPrint(("Enter HelloWDMAddDevice\n"));

    NTSTATUS status;
    PDEVICE_OBJECT fdo;
    UNICODE_STRING devName;
    RtlInitUnicodeString(&devName,L"\\Device\\MyWDMDevice");//设备名称,设备名称只能被内核模式下的其他驱动所识别。

    //创建FDO(Function Device Object)
    status = IoCreateDevice(
        DriverObject,
        sizeof(DEVICE_EXTENSION),
        &(UNICODE_STRING)devName,
        FILE_DEVICE_UNKNOWN,
        0,
        FALSE,
        &fdo);
    if( !NT_SUCCESS(status))
        return status;
    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
    pdx->fdo = fdo;
    //将FDO附加在PDO上面,并且将Extension中的NextStackDevice指向FDO的下层设备。如果PDO上面有过滤驱动的话,NextStackDevice就是过滤驱动,如果没有就是PDO。
    pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
    UNICODE_STRING symLinkName;
    //创建链接符号,这样用户模式的应用就可以访问此设备。内核模式下,符号链接是以\??\开头的(或者\DosDevices\)。用户模式下则是\\.\开头。
    //这里就可以在用户模式下用\\.\HelloWDM来访问本设备。
    RtlInitUnicodeString(&symLinkName,L"\\DosDevices\\HelloWDM");

    pdx->ustrDeviceName = devName;
    pdx->ustrSymLinkName = symLinkName;
    status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);

    if( !NT_SUCCESS(status))
    {
        IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
        status = IoCreateSymbolicLink(&symLinkName,&devName);
        if( !NT_SUCCESS(status))
        {
            return status;
        }
    }

    fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;//DO_BUFFERED_IO,定义为“缓冲内存设备”
    fdo->Flags &= ~DO_DEVICE_INITIALIZING;//将Flag上的DO_DEVICE_INITIALIZING位清零,保证设备初始化完毕,必须的。

    KdPrint(("Leave HelloWDMAddDevice\n"));
    return STATUS_SUCCESS;
}

/************************************************************************
* 函数名称:DefaultPnpHandler
* 功能描述:对PNP IRP进行缺省处理
* 参数列表:
      pdx:设备对象的扩展
      Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/ 
#pragma PAGEDCODE
NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)
{
    PAGED_CODE();
    KdPrint(("Enter DefaultPnpHandler\n"));
    IoSkipCurrentIrpStackLocation(Irp);
    KdPrint(("Leave DefaultPnpHandler\n"));
    return IoCallDriver(pdx->NextStackDevice, Irp);//将irp传递给下层驱动
}

/************************************************************************
* 函数名称:HandleRemoveDevice
* 功能描述:对IRP_MN_REMOVE_DEVICE IRP进行处理
* 参数列表:
      fdo:功能设备对象
      Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
{
    PAGED_CODE();
    KdPrint(("Enter HandleRemoveDevice\n"));

    //设置IRP的完成状态。
    Irp->IoStatus.Status = STATUS_SUCCESS;
    //将IRP请求向底层驱动转发。
    NTSTATUS status = DefaultPnpHandler(pdx, Irp);

    //删除符号链接
    IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);

    //调用IoDetachDevice()把fdo从设备栈中脱开:
    if (pdx->NextStackDevice)
        IoDetachDevice(pdx->NextStackDevice);
    
    //删除fdo:
    IoDeleteDevice(pdx->fdo);
    KdPrint(("Leave HandleRemoveDevice\n"));
    return status;
}

/************************************************************************
* 函数名称:HelloWDMPnp
* 功能描述:对即插即用IRP进行处理
* 参数列表:
      fdo:功能设备对象
      Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
                        IN PIRP Irp)
{
    PAGED_CODE();

    KdPrint(("Enter HelloWDMPnp\n"));
    NTSTATUS status = STATUS_SUCCESS;
    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;//DEVICE_EXTENSION是在AddDevice里面创建的。
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);//获取irp信息
    switch (stack->MinorFunction)//根据PNP irp的minor function code来调用相应的处理函数。
    {
    case IRP_MN_REMOVE_DEVICE:
        status = HandleRemoveDevice(pdx, Irp);
        break;
    default:
        status = DefaultPnpHandler(pdx, Irp);
        break;
    }
    
    KdPrint(("Leave HelloWDMPnp\n"));
    return status;
}

/************************************************************************
* 函数名称:HelloWDMDispatchRoutine
* 功能描述:对缺省IRP进行处理
* 参数列表:
      fdo:功能设备对象
      Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo,
                                 IN PIRP Irp)
{
    PAGED_CODE();
    KdPrint(("Enter HelloWDMDispatchRoutine\n"));
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    //打印IRP的major function code和minor function code。
    ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
    KdPrint(("DispatchRoutine, Major function code: %x, Minor function code: %x, control code: %x\n", 
        stack->MajorFunction, stack->MinorFunction, code));

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;    // no bytes xfered
    IoCompleteRequest( Irp, IO_NO_INCREMENT );
    KdPrint(("Leave HelloWDMDispatchRoutine\n"));
    return STATUS_SUCCESS;
}

/************************************************************************
* 函数名称:HelloWDMUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
      DriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
{
    PAGED_CODE();
    KdPrint(("Enter HelloWDMUnload\n"));
    KdPrint(("Leave HelloWDMUnload\n"));
}

复制代码

     B、准备文件: makefile . 内容如下:

# 此文件 一般情况下只有一行 并且不需要修改 不能有前导空格 
!INCLUDE $(NTMAKEENV)\makefile.def

    C、准备文件: SOURCES, 内容如下:

复制代码

#下边这行指定生成驱动名字HelloWorld.sys
TARGETNAME=HelloWorld
#下边这行指定生成文件的类型DRIVER指驱动
TARGETTYPE=DRIVER
#下边这行指定生成驱动所在的路径\SYS\HelloWorld.sys
TARGETPATH=SYS
#下边这行指定相关头文件所在目录路径
INCLUDES=$(BASEDIR)\inc;\
      $(BASEDIR)\inc\wxp;\ 

##上边必空一行H:\WINDDK3790(DDK目录) 等价$(BASEDIR)
#下边这行指定驱动源代码*.cpp或者*.c
SOURCES=HelloWorld.c\

复制代码

 ---- 上面的文件准备完毕后,大概是这样的--------

5、 编译

    依次 点击 : 开始  ->  所有程序  ->   windows driver kits -> WDK 7600.16385.1 ->    Build Environments  -> Windows 7 ->   x64 Free Build Environment   

    A、 键入命令,使终端来到 上面 4 的所在文件夹: C:\demo

    B、执行 构建命令: 键入  build  , 回车执行构建。 

 

   构建结束后,demo目录下会大概是这样的:

   6、执行文件 签名。

         尽管我开启了 win7测试模式 (管理员控制台执行命令:bcdedit /set testsigning on,  再重启 ),没有签名的驱动是无法运行的。

        A、找到 5 中生成的驱动文件: helloworld.sys。  

 

      B、使用 debugview工具查看内核输出 (请勾选: 菜单-> capture  ->  capture kernel 选项), 使用 DriverMonitor 加载驱动。

      先来一张没有签名驱动的截图,发现驱动无法加载, 内核自然也没有输出。

  同时查看驱动文件的属性,也无法找到关于签名的信息:

       C、签名驱动

         使用软件  64Signer   对驱动文件进行签名。    签名后,就会发现 驱动文件的属性页中出现了 关于签名的tab页。

7、驱动加载与卸载

     驱动签名后,使用 driver monitor 和 debugview工具查看驱动内核输出。得到如下结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值