• 创建一个基础WDM驱动,并使用MFC调用驱动


    首先参考文章:如何使用WinDbg和Virtual Box进行Windows驱动debug,搭建开发环境。

    创建一个Empty WDM项目,在solution下添加一个MFC项目:
    在这里插入图片描述
    其中FirstDriver是一个简单的WDM驱动项目,而App是一个MFC程序,用于调用驱动。

    Source.c是驱动源码:

    #include "ntddk.h"
    
    #define DEVICE_SEND CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)
    #define DEVICE_REC CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA)
    
    UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\mydevice123");
    UNICODE_STRING SymLinkName = RTL_CONSTANT_STRING(L"\\??\\mydevicelink123");
    PDEVICE_OBJECT DeviceObject = NULL;
    
    VOID Unload(IN PDRIVER_OBJECT DriverObject) {
    	IoDeleteSymbolicLink(&SymLinkName);
    	IoDeleteDevice(DeviceObject);
    	DbgPrint("Driver unload\r\n");
    }
    
    NTSTATUS DispatchPassThru(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
       PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
       NTSTATUS status = STATUS_SUCCESS;
    
       switch (irpsp->MajorFunction) {
       case IRP_MJ_CREATE:
          DbgPrint("Create request\r\n");
          /*KdPrint(("Create request\r\n"));*/
          break;
       case IRP_MJ_CLOSE:
          DbgPrint("Close request\r\n");
          /*KdPrint(("Close request\r\n"));*/
          break;
       //case IRP_MJ_READ:
       //   DbgPrint("Read request\r\n");
       //   KdPrint(("Read request\r\n"));
       //   break;
       default:
          status = STATUS_INVALID_PARAMETER;
          break;
       }
    
       Irp->IoStatus.Information = 0;
       Irp->IoStatus.Status = status;
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
       return status;
    }
    
    NTSTATUS DispathDevCTL(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
       PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
       NTSTATUS status = STATUS_SUCCESS;
       ULONG returnLength = 0;
    
       PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
       ULONG inLength = irpsp->Parameters.DeviceIoControl.InputBufferLength;
       ULONG outLength = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
    
       WCHAR *demo = L"sample return from driver";
    
       switch (irpsp->Parameters.DeviceIoControl.IoControlCode) {
       case DEVICE_SEND:
          DbgPrint("Send data is %ws \r\n", buffer);
          returnLength = (wcsnlen(buffer, 511) + 1) * 2;
          break;
       case DEVICE_REC:
          wcsncpy(buffer, demo, 511);
          returnLength = (wcsnlen(buffer, 511) + 1) * 2;
          DbgPrint("receive data is %ws \r\n", buffer);
          break;
       default:
          status = STATUS_INVALID_PARAMETER;
       }
    
       Irp->IoStatus.Status = status;
       Irp->IoStatus.Information = returnLength;
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
       return status;
    }
    
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) // main
    {
    	DriverObject->DriverUnload = Unload;
    
    	UNICODE_STRING string = RTL_CONSTANT_STRING(L"hello driver\r\n");
    	DbgPrint("%wZ", &string); // printf()
    
    	NTSTATUS status = IoCreateDevice(DriverObject, 0, &DeviceName,
    		FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN,
    		FALSE, &DeviceObject);
    
    	if (!NT_SUCCESS(status)) {
    		DbgPrint("Create device failed\r\n");
    		return status;
    	}
    
    	status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);
    
    	if (!NT_SUCCESS(status)) {
    		DbgPrint("create symbolic link failed\r\n");
    		IoDeleteDevice(DeviceObject);
    		return status;
    	}
    
       for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i) {
          DriverObject->MajorFunction[i] = DispatchPassThru;
       }
    
       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispathDevCTL;
    
    	DbgPrint("Driver load\r\n");
    
    	return STATUS_SUCCESS;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    程序完成了几项工作:

    1. 定义了Device Control Code,读写code分别为0x801和0x802,微软为用户开放了0x800~0xfff的control code;
    2. 定义了DeviceName和SymbolLinkName,device/symbolink name一旦创建成功,可以通过WinObj查看,这个工具可以查看系统中的Device和用于用户调用(File IO) device别名symbolink name:
      在这里插入图片描述
      在这里插入图片描述
    3. DriverEntry入口函数创建了device和symbolink,并配置了分派函数用于响应用户的各种请求。
    4. DispatchPassThru函数响应IRP,处理了Device open和close请求。
    5. DispatchDevCTL函数响应用户的IO请求。具体是指读写请求,这里会用到之前定义的Device Control Code。
    6. Unload函数删除symbolink和device对象。

    MFC应用程序
    界面:
    在这里插入图片描述
    一共4个按钮,分别执行device open/close,以及通过IO发送和接收数据。

    #include "winioctl.h"
    
    #define DEVICE_SEND CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)
    #define DEVICE_REC CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA)
    
    HANDLE devicehandle = NULL;
    
    void CAppDlg::OnBnClickedButton1()
    {
       // TODO: Add your control notification handler code here
       devicehandle = CreateFile(L"\\\\.\\mydevicelink123", 
          GENERIC_ALL, 0, 0, 
          OPEN_EXISTING, 
          FILE_ATTRIBUTE_SYSTEM,
          0);
       if (devicehandle == INVALID_HANDLE_VALUE) {
          MessageBox(L"Not valid value", 0, 0);
          return;
       }
    
       MessageBox(L"valid value", 0, 0);
    }
    
    
    void CAppDlg::OnBnClickedButton2()
    {
       // TODO: Add your control notification handler code here
       if (devicehandle != INVALID_HANDLE_VALUE) {
          CloseHandle(devicehandle);
       }
    }
    
    
    void CAppDlg::OnBnClickedButton3()
    {
       // TODO: Add your control notification handler code here
       WCHAR *message = L"send sample from mfc";
       WCHAR returnMessage[1024] = { 0 };
       ULONG returnLength = 0;
       char wr[4] = { 0 };
       if (devicehandle != NULL && devicehandle != INVALID_HANDLE_VALUE) {
    
          if (!DeviceIoControl(devicehandle, DEVICE_SEND, message,
             (wcslen(message) + 1) * 2,
             returnMessage,
             1024,
             &returnLength,
             0)) {
             MessageBox(L"Device io control failed", 0, 0);
          }
          else {
             MessageBox(returnMessage, 0, 0);
             _itoa_s(returnLength, wr, 10);
             MessageBoxA(0, wr, 0, 0);
          }
       }
    }
    
    
    void CAppDlg::OnBnClickedButton4()
    {
       // TODO: Add your control notification handler code here
       WCHAR message[1024] = { 0 };
       ULONG returnLength = 0;
    
       if (devicehandle != NULL && devicehandle != INVALID_HANDLE_VALUE) {
    
          if (!DeviceIoControl(devicehandle, DEVICE_REC, NULL,
             0,
             message,
             1024,
             &returnLength,
             0)) {
             MessageBox(L"Device io control failed", 0, 0);
          }
          else {
             MessageBox(message, 0, 0);
          }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    需要注意的是,这里要使用DeviceIoControl函数用于和device进行IO控制,所以include头文件winioctl.h,并且Device control code要和WDM驱动里的code一致。
    将编译好的driver.sys和App放入虚拟机,以管理员权限打开OSRLOADER,Register Service和Start Service,以管理员权限打开App,点击4个按钮,依次显示如下:
    在这里插入图片描述

  • 相关阅读:
    Spring和SpringBoot中的@Component 和@ComponentScan注解用法介绍和注意事项
    RHCE学习 --- 第八次作业(ansible)
    全新接口——邻家好货 API
    为什么很多新型编程语言都抛弃了 C 语言风格的 for 语句?
    【计算机视觉40例】案例17:求解数独图像
    <TypeScript系列>: TS类型声明declare .d.ts文件
    k线图基础知识图解——单根K线的含义
    Java计算机毕业设计实验室耗材管理系统源码+系统+数据库+lw文档
    【虹科干货】TWAMP:什么是双向主动测量协议?
    HTTP 协议简介
  • 原文地址:https://blog.csdn.net/u014786409/article/details/125404187