栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

创建一个基础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 unloadrn");
}

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 requestrn");
      
      break;
   case IRP_MJ_CLOSE:
      DbgPrint("Close requestrn");
      
      break;
   //case IRP_MJ_READ:
   //   DbgPrint("Read requestrn");
   //   KdPrint(("Read requestrn"));
   //   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 rn", 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 rn", 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 driverrn");
	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 failedrn");
		return status;
	}

	status = IoCreateSymbolicLink(&SymLinkName, &DeviceName);

	if (!NT_SUCCESS(status)) {
		DbgPrint("create symbolic link failedrn");
		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 loadrn");

	return STATUS_SUCCESS;
}

程序完成了几项工作:

  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);
      }
   }
}

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/982267.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号