驱动编程学习一

   环境设置:
1、属性页->C/++->警告等级:等级3/W
2、属性页->C/C++-)将警告视为错误:否/x-
3、属性页->Inf2Cat->Run Inf2Cat:否
4、属性页->Driver settings->Target os Version:设置版本 windows 7 windows1e任选
5、属性页->Driver Settings->Target PlatForm:Desktop
6、属性页->StampInf->Endable Architecture:否
7、KdPrint类似于控制台的printf
8、DriverEntry类似于C/C++里的main

 

一、第一个简单的驱动编程

#include <ntifs.h>
//
卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //调用创建驱动设备函数 CreateDevice CreateDevice(driver); return STATUS_SUCCESS; };//最小的驱动 只有一行代码。

二、创建驱动设备对象

//创建驱动设备对象
NTSTATUS CreateDevice(PDRIVER_OBJECT driver)
{
    NTSTATUS status;
    UNICODE_STRING MyDriver;//char*wchar*
    PDEVICE_OBJECT device = NULL;  //这是一个指针
    RtlInitUnicodeString(&MyDriver,L"\\DEVICE\VayDriver");//strcpy//ucscpy,初始化字符串对象

    KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));

    status = IoCreateDevice(driver,
        4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小
        &MyDriver,    // 设备名字
        FILE_DEVICE_UNKNOWN,//设备的类型
        FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE
        FALSE,
        &device);//device 返回设备对象
    
    if (status == STATUS_SUCCESS)
    {
        KdPrint(("jw:驱动设备对象创建成功,ok \n"));
     }
    else {
        KdPrint(("jw:驱动设备对象创建失败,删除设备 \n"));
        IoDeleteDevice(device);
    }
    KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));
    return status;
}

//卸载驱动
void Unload(PDRIVER_OBJECT driver)
{//因为参数driver没有使用,会出现警告。
    IoDeleteDevice(driver->DeviceObject);
    KdPrint(("jw:进入卸载例程"));
}
//驱动入口点函数
NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg)
{
    KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++"));
    KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径
    driver->DriverUnload = Unload;//注册卸载例程
    //调用创建驱动设备函数 CreateDevice
    CreateDevice(driver);
    return STATUS_SUCCESS;
};//最小的驱动  只有一行代码。

三、为设备对象创建符号链接

#define  符号链接名字 L"\\??\\mylinkName"
#define  驱动设备名字 L"\\DEVICE\uzDriverName001"
//创建驱动设备对象
NTSTATUS CreateDevice(PDRIVER_OBJECT driver)
{
    NTSTATUS status;
    UNICODE_STRING uzDriverName;//char*wchar*
    PDEVICE_OBJECT device = NULL;  //这是一个指针
    RtlInitUnicodeString(&uzDriverName, 驱动设备名字);//strcpy//ucscpy,初始化字符串对象

    KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));

    status = IoCreateDevice(driver,
        4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小
        &uzDriverName,    // 设备名字
        FILE_DEVICE_UNKNOWN,//设备的类型
        FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE
        FALSE,
        &device);//device 返回设备对象
    
    if (status == STATUS_SUCCESS)
    {
        KdPrint(("jw:驱动设备对象创建成功,ok \n"));
        //创建设备对象之后就可以为驱动对象绑定符号链接,就是为设备创建一个别名
        UNICODE_STRING uzMyLinsName;    //符号链接名字
        RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串
        status = IoCreateSymbolicLink(&uzMyLinsName, &uzDriverName);
        if (status == STATUS_SUCCESS)
        {
            KdPrint(("jw:创建符号链接 符号链接名= %wZ 成功\r\n", &uzMyLinsName));
        }else{
            IoDeleteSymbolicLink(&uzMyLinsName);//删除符号链接
            KdPrint(("jw:创建符号链接失败 错误代码=%X \r\n", status));//错误就是状态码
        }
    }
    else {
        KdPrint(("jw:驱动设备对象创建失败,删除设备 \n"));
        IoDeleteDevice(device);
    }
    KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));
    return status;
}

//卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。 //一定要在删除设备前 先删除符号链接 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 IoDeleteSymbolicLink(&uzMyLinsName); //删除设备对象 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //调用创建驱动设备函数 CreateDevice CreateDevice(driver); return STATUS_SUCCESS; };//最小的驱动 只有一行代码。

四、访问驱动设备及IRP事件处理

#define  符号链接名字 L"\\??\\mylinkName"       //这个是用户层访问的CreateFile
#define  驱动设备名字 L"\\DEVICE\uzDriverName001"         //这是内核访问的NtCreateFile
//创建驱动设备对象
NTSTATUS CreateDevice(PDRIVER_OBJECT driver)
{
    NTSTATUS status;
    UNICODE_STRING uzDriverName;//char*wchar*
    PDEVICE_OBJECT device = NULL;  //这是一个指针
    RtlInitUnicodeString(&uzDriverName, 驱动设备名字);//strcpy//ucscpy,初始化字符串对象

    KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));

    status = IoCreateDevice(driver,
        4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小
        &uzDriverName,    // 设备名字
        FILE_DEVICE_UNKNOWN,//设备的类型
        FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE
        FALSE,
        &device);//device 返回设备对象
    
    if (status == STATUS_SUCCESS)
    {
        KdPrint(("jw:驱动设备对象创建成功,ok \n"));
        //创建设备对象之后就可以为驱动对象绑定符号链接,就是为设备创建一个别名
        UNICODE_STRING uzMyLinsName;    //符号链接名字
        RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串
        status = IoCreateSymbolicLink(&uzMyLinsName, &uzDriverName);
        if (status == STATUS_SUCCESS)
        {
            KdPrint(("jw:创建符号链接 符号链接名= %wZ 成功\r\n", &uzMyLinsName));
        }else{
            IoDeleteSymbolicLink(&uzMyLinsName);//删除符号链接
            KdPrint(("jw:创建符号链接失败 错误代码=%X \r\n", status));//错误就是状态码
        }
    }
    else {
        KdPrint(("jw:驱动设备对象创建失败,删除设备 \n"));
        IoDeleteDevice(device);
    }
    KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));
    return status;
}

//访问驱动设备及IRP事件处理
//https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/irp-major-function-codes
NTSTATUS IRP_PROC(PDEVICE_OBJECT device, PIRP pirp)//irp回调函数
{//常用的三个处理
    KdPrint(("jw:进入派遣函数"));
    PIO_STACK_LOCATION irpStack;
    ULONG CtlCode;
    ULONG InputBuffLength;

    irpStack = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的消息

    switch (irpStack->MajorFunction)
    {//分发消息
    case IRP_MJ_DEVICE_CONTROL:  //DeviceIoControl
    {
        KdPrint(("jw:用户层调用了 DeviceIoControl"));
        break;
    }
    case IRP_MJ_CREATE:   //CreateFile
    {
        KdPrint(("jw:用户层调用了 CreateFile "));
        break;
    }
    case IRP_MJ_CLOSE:   //CloseHandle
    {
        KdPrint(("jw:用户层调用了 CloseHandle"));
    }
    }

    pirp->IoStatus.Status = STATUS_SUCCESS;
    pirp->IoStatus.Information = 4;  //返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned
    IoCompleteRequest(pirp, IO_NO_INCREMENT);  //调用方已完成所有I/O请求处理操作  并且不增加优先级
    KdPrint(("jw:离开派遣函数 \r\n"));
    return STATUS_SUCCESS;
};

//卸载驱动
void Unload(PDRIVER_OBJECT driver)
{//因为参数driver没有使用,会出现警告。
    //一定要在删除设备前 先删除符号链接
    UNICODE_STRING uzMyLinsName;    //符号链接名字
    RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串
    IoDeleteSymbolicLink(&uzMyLinsName);
    //删除设备对象
    IoDeleteDevice(driver->DeviceObject);
    KdPrint(("jw:进入卸载例程"));
}

//驱动入口点函数
NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg)
{
    KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++"));
    KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径
    driver->DriverUnload = Unload;//注册卸载例程
    //irp处理
    driver->MajorFunction[IRP_MJ_CREATE] = IRP_PROC;
    driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_PROC;
    driver->MajorFunction[IRP_MJ_CLOSE] = IRP_PROC;

    //调用创建驱动设备函数 CreateDevice
    CreateDevice(driver);//创建驱动设备
    return STATUS_SUCCESS;
};//最小的驱动  只有一行代码。

另建一个对话框程序exe来调用上面的驱动例程,建立2个按钮

 

HANDLE g_sysHandle = NULL;
#define  符号链接名字 L"\\??\\mylinkName"       //这个是用户层访问的CreateFile
//第一个按钮事件
void C驱动用户层访问Dlg::OnBnClickedBtnCreate() { // 打开驱动设备对象,就是获取一个驱动设备的句柄 g_sysHandle = CreateFileW(符号链接名字, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); TRACE(TEXT("jw:sysHandle = %p Error = %d \r\n"), g_sysHandle, GetLastError()); } //第二个按钮事件 void C驱动用户层访问Dlg::OnBnClickedBtnUnload() { // 卸载打开的驱动句柄 TRACE(TEXT("jw:卸载打开的驱动句柄 \r\n")); CloseHandle(g_sysHandle);//只有释放掉此句柄,驱动才能正常卸载。或者当拥有此句柄的进程 关闭了 }

五、用户层与驱动进行通信

#include <ntifs.h>

#define  符号链接名字 L"\\??\\mylinkName"       //这个是用户层访问的CreateFile
#define  驱动设备名字 L"\\DEVICE\uzDriverName001"         //这是内核访问的NtCreateFile
//创建驱动设备对象
NTSTATUS CreateDevice(PDRIVER_OBJECT driver)
{
    NTSTATUS status;
    UNICODE_STRING uzDriverName;//char*wchar*
    PDEVICE_OBJECT device = NULL;  //这是一个指针
    RtlInitUnicodeString(&uzDriverName, 驱动设备名字);//strcpy//ucscpy,初始化字符串对象

    KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));

    status = IoCreateDevice(driver,
        4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小
        &uzDriverName,    // 设备名字
        FILE_DEVICE_UNKNOWN,//设备的类型
        FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE
        FALSE,
        &device);//device 返回设备对象
    
    if (status == STATUS_SUCCESS)
    {
        KdPrint(("jw:驱动设备对象创建成功,ok \n"));
        //创建设备对象之后就可以为驱动对象绑定符号链接,就是为设备创建一个别名
        UNICODE_STRING uzMyLinsName;    //符号链接名字
        RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串
        status = IoCreateSymbolicLink(&uzMyLinsName, &uzDriverName);
        if (status == STATUS_SUCCESS)
        {
            KdPrint(("jw:创建符号链接 符号链接名= %wZ 成功\r\n", &uzMyLinsName));
        }else{
            IoDeleteSymbolicLink(&uzMyLinsName);//删除符号链接
            KdPrint(("jw:创建符号链接失败 错误代码=%X \r\n", status));//错误就是状态码
        }
    }
    else {
        KdPrint(("jw:驱动设备对象创建失败,删除设备 \n"));
        IoDeleteDevice(device);
    }
    KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device));
    return status;
}

//访问驱动设备及IRP事件处理
//https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/irp-major-function-codes

NTSTATUS IRP_PROC(PDEVICE_OBJECT device, PIRP pirp)//irp回调函数
{//常用的三个处理
    KdPrint(("jw:进入派遣函数"));
    PIO_STACK_LOCATION irpStack;
    ULONG CtlCode;
    ULONG InputBuffLength;

    irpStack = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的消息

    switch (irpStack->MajorFunction)
    {//分发消息
    case IRP_MJ_DEVICE_CONTROL:  //DeviceIoControl
    {
        //case irpStack->Parameters.DeviceIoControl.IoControlCode:
        //
        //这里取出用户层传递过来的缓冲区的数据
        char *pInbuf = (char *)pirp->AssociatedIrp.SystemBuffer;
        //取出缓冲区大小
        KdPrint(("jw:pInbuf = %s \r\n", pInbuf));
        KdPrint(("jw:用户层调用了 DeviceIoControl"));
        //返回数据给缓冲区
        strcpy(pInbuf, "这个数据是驱动返回给用户层的。\r\n");
        pirp->IoStatus.Status = STATUS_SUCCESS;
        pirp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;  //返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned
        IoCompleteRequest(pirp, IO_NO_INCREMENT);  //调用方已完成所有I/O请求处理操作  并且不增加优先级
        break;
    }
    case IRP_MJ_CREATE:   //CreateFile
    {
        KdPrint(("jw:用户层调用了 CreateFile "));
        break;
    }
    case IRP_MJ_CLOSE:   //CloseHandle
    {
        KdPrint(("jw:用户层调用了 CloseHandle"));
    }
    }

    KdPrint(("jw:离开派遣函数 \r\n"));
    return STATUS_SUCCESS;
};

//卸载驱动
void Unload(PDRIVER_OBJECT driver)
{//因为参数driver没有使用,会出现警告。//一定要在删除设备前 先删除符号链接
    UNICODE_STRING uzMyLinsName;    //符号链接名字
    RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串
    IoDeleteSymbolicLink(&uzMyLinsName);
    //删除设备对象
    IoDeleteDevice(driver->DeviceObject);
    KdPrint(("jw:进入卸载例程"));
}

//驱动入口点函数
NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg)
{
    KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++"));
    KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径
    driver->DriverUnload = Unload;//注册卸载例程
    //irp处理
    driver->MajorFunction[IRP_MJ_CREATE] = IRP_PROC;
    driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_PROC;
    driver->MajorFunction[IRP_MJ_CLOSE] = IRP_PROC;

    //调用创建驱动设备函数 CreateDevice
    CreateDevice(driver);//创建驱动设备
    return STATUS_SUCCESS;
};//最小的驱动  只有一行代码。

用户层  在上面对话框工程中,再添加一个按钮

//传递一个字符串给驱动
#include <winioctl.h>
#define  IO_STRING  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803,METHOD_BUFFERED,FILE_ANY_ACCESS)   //控制码测试
#define  IO_IS_OK_TEST  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804,METHOD_BUFFERED,FILE_ANY_ACCESS)   //控制码测试
#define  IO_IS_OK_TEST  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805,METHOD_BUFFERED,FILE_ANY_ACCESS)   //控制码测试

void C驱动用户层访问Dlg::OnBnClickedBtnClIo()//与驱动通信
{
    //打开设备,获取设备句柄
    HANDLE sysHandle = CreateFileW(符号链接名字,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    //传递字符串到设备。
    char testString[100] = "测试字符串 R3至R0 ";
    char  retBuf[256] = { 0 };
    DWORD  dwRetSize = 0;
    BOOL br = DeviceIoControl(sysHandle,//CreateFileW 打开驱动设备 返回的句柄
        IO_STRING,//控制码 CTL_CODE
        &testString,  //输入缓冲区指针   驱动中在irp中的 IRP_MJ_DEVICE_CONTROL中处理放入缓冲区的数据
        sizeof(testString), //输入缓冲区大小,直接写100也可以
        retBuf,//返回缓冲区的地址
        256,  //返回缓冲区的大小
        &dwRetSize, //返回字节数
        NULL);
    //返回值 
    TRACE("jw:retBuf = %s \r\n", retBuf);//
    //另一种方式打印数据
    char buf[1024] = { 0 };
    sprintf_s(buf, "jw:retBuf = %s \r\n", retBuf);
    OutputDebugStringA(buf);//用调试输出
}

 

posted on 2022-11-19 17:45  悠心不已  阅读(31)  评论(0)    收藏  举报

导航