当前位置:网站首页>驱动与应用程序通信
驱动与应用程序通信
2022-07-03 15:20:00 【宇龍_】
前言
本文讲述的是Windows操作系统下驱动程序与应用程序之间的通信,说简单点就是相互发送数据。
正文
在应用程序中,可以通过CreateFile来打开设备,然后通过DeviceIoControl来向驱动发送或接收数据;而驱动程序则需要通过创建控制设备对象,并创建符号链接,通过分发函数来处理应用程序的数据,总之按这个流程来就完事儿了,还是相对比较简单,直接上代码,不清楚的可以留言。
注意:
关于符号链接和设备对象是否创建成功,可以通过微软提供的winobj工具进行查看
【WinObj - Windows Sysinternals | Microsoft Docs】
驱动的注册、加载则可以使用KmdManager工具完成。
实例
应用程序代码(main.cpp):
#include <iostream>
#include <Windows.h>
#define DEVICE_NAME L"\\\\.\\MsgCenterKernal"
//读设备
#define READ_CTL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_READ_ACCESS)
//写设备
#define WRITE_CTL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x831,METHOD_BUFFERED,FILE_WRITE_ACCESS)
DWORD WriteDevice(HANDLE hDevice, char *szBuff, DWORD dwLen)
{
DWORD dwWrite = 0;
DeviceIoControl(hDevice, WRITE_CTL_CODE, szBuff, dwLen, NULL, 0, &dwWrite, NULL);
return dwWrite;
}
DWORD ReadDevice(HANDLE hDevice, char *szBuff, DWORD dwLen)
{
DWORD dwRead = 0;
DeviceIoControl(hDevice, READ_CTL_CODE, NULL, 0, szBuff, dwLen, &dwRead, NULL);
return dwRead;
}
int main()
{
HANDLE hDevice = CreateFile(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_DEVICE, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("open Device error!\n");
return 0;
}
do
{
char szData[100] = "Hello Driver,I am App!";
char szCache[1024];
system("pause");
//DeviceIoControl read write
DWORD dwWriteNumber = WriteDevice(hDevice, szData, strlen(szData)+1);
printf("DeviceIoControl Write:%s,size:%d\n",szData,dwWriteNumber);
system("pause");
memset(szCache, 0, sizeof(szCache));
DWORD dwReadNumber = ReadDevice(hDevice, szCache, sizeof(szCache) - 1);
printf("DeviceIoControl Read:%s,size:%d\n", szCache, dwReadNumber);
system("pause");
} while (FALSE);
CloseHandle(hDevice);
return 0;
}驱动程序代码(Driver.c):
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\MsgCenterKernal"
#define SYMBOLIC_LINK_NAME L"\\??\\MsgCenterKernal"
//读设备
#define READ_CTL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_BUFFERED,FILE_READ_ACCESS)
//写设备
#define WRITE_CTL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x831,METHOD_BUFFERED,FILE_WRITE_ACCESS)
//全局变量
//设备控制对象
PDEVICE_OBJECT g_pControlDeviceObj = NULL;
void DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("Driver Unload...\n");
UNICODE_STRING strSymbolicLinkName;
RtlInitUnicodeString(&strSymbolicLinkName, SYMBOLIC_LINK_NAME);
IoDeleteSymbolicLink(&strSymbolicLinkName);
if (pDriverObject->DeviceObject)
{
IoDeleteDevice(pDriverObject->DeviceObject);
g_pControlDeviceObj = NULL;
}
}
NTSTATUS OnMsgDispatch(PDEVICE_OBJECT pDeviceObject, IRP* pIrp)
{
NTSTATUS nStatus = STATUS_SUCCESS;
ULONG lRetLen = 0;
//请求当前栈空间
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//判断是否是发送给控制设备对象的
if (pDeviceObject == g_pControlDeviceObj)
{
do
{
//判断请求的种类
//打开和关闭都返回成功
if (stack->MajorFunction == IRP_MJ_CREATE || stack->MajorFunction == IRP_MJ_CLOSE)
{
break;
}
//处理DeviceIoControl
if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
//根据IoControlCode进行处理
ULONG ioControlCode = stack->Parameters.DeviceIoControl.IoControlCode;
//数据
PVOID pBuffer = pIrp->AssociatedIrp.SystemBuffer;
//输入内核的数据大小
ULONG lInLen = stack->Parameters.DeviceIoControl.InputBufferLength;
//内核输出的数据大小
ULONG lOutLen = stack->Parameters.DeviceIoControl.OutputBufferLength;
switch (ioControlCode)
{
case WRITE_CTL_CODE:
{
//读取发送到内核的数据
if (pBuffer != NULL && lInLen > 0)
{
//一般要对输入的数据大小进行判断,超过长度的的就返回错误!这里未做相关处理
DbgPrint("App write to Driver size:%d,data:%s", lInLen, pBuffer);
//更新内核处理的数据大小
lRetLen = lInLen;
}
break;
}
case READ_CTL_CODE:
{
//内核发送到应用层
DbgPrint("app want to read from driver size:%d", lOutLen);
const char*pData = "Hello App,I am Driver";
int len = strlen(pData) + 1;
memcpy(pBuffer, pData, len);
//更新内核处理的数据大小
lRetLen = len;
break;
}
default:
{
//不接受的请求,一律返回非法
nStatus = STATUS_INVALID_PARAMETER;
break;
}
}
break;
}
//剩余一律返回参数错误
nStatus = STATUS_INVALID_PARAMETER;
} while (FALSE);
}
//结束请求
pIrp->IoStatus.Information = lRetLen;
pIrp->IoStatus.Status = nStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return nStatus;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
NTSTATUS nStatus = STATUS_UNSUCCESSFUL;
DbgPrint("Driver Entry...\n");
do
{
UNICODE_STRING strDeviceName, strSymbolLinkName;
RtlInitUnicodeString(&strDeviceName, DEVICE_NAME);
RtlInitUnicodeString(&strSymbolLinkName, SYMBOLIC_LINK_NAME);
//或替换成IoCreateDeviceSecure
nStatus = IoCreateDevice(pDriverObject, 0, &strDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &g_pControlDeviceObj);
if (!NT_SUCCESS(nStatus))
{
DbgPrint("Create Device Object Error:%x\n",nStatus);
break;
}
g_pControlDeviceObj->Flags |= DO_BUFFERED_IO;
//创建符号链接
nStatus = IoCreateSymbolicLink(&strSymbolLinkName, &strDeviceName);
if (!NT_SUCCESS(nStatus))
{
DbgPrint("Create SymbolicLink Error:%x\n", nStatus);
IoDeleteDevice(g_pControlDeviceObj);
g_pControlDeviceObj = NULL;
break;
}
//设置统一的分发函数
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i)
{
pDriverObject->MajorFunction[i] = OnMsgDispatch;
}
pDriverObject->DriverUnload = DriverUnload;
} while (FALSE);
return nStatus;
}
边栏推荐
- Didi off the shelf! Data security is national security
- SQL server installation location cannot be changed
- Redis cache penetration, cache breakdown, cache avalanche solution
- 【pytorch学习笔记】Datasets and Dataloaders
- redis单线程问题强制梳理门外汉扫盲
- Dataframe returns the whole row according to the value
- [attention mechanism] [first vit] Detr, end to end object detection with transformers the main components of the network are CNN and transformer
- C语言刷题~Leetcode与牛客网简单题
- Visual upper system design and development (Halcon WinForm) -5 camera
- 整形和浮点型是如何在内存中的存储
猜你喜欢

Jvm-05-object, direct memory, string constant pool

Reentrantlock usage and source code analysis

Characteristics of MySQL InnoDB storage engine -- Analysis of row lock

Matplotlib drawing label cannot display Chinese problems

What is embedding (encoding an object into a low dimensional dense vector), NN in pytorch Principle and application of embedding

Visual upper system design and development (Halcon WinForm) -5 camera

Visual host system design and development (Halcon WinForm)

Redis主从、哨兵、集群模式介绍

【云原生训练营】模块七 Kubernetes 控制平面组件:调度器与控制器

百度智能云助力石嘴山市升级“互联网+养老服务”智慧康养新模式
随机推荐
Finally, someone explained the financial risk management clearly
The markdown file obtains the pictures of the network and stores them locally and modifies the URL
视觉上位系统设计开发(halcon-winform)-1.流程节点设计
leetcode_ Power of Four
Kubernetes 进阶训练营 Pod基础
什么是embedding(把物体编码为一个低维稠密向量),pytorch中nn.Embedding原理及使用
Kubernetes will show you from beginning to end
The state does not change after the assignment of El switch
Solve the problem that pushgateway data will be overwritten by multiple push
Redis single thread problem forced sorting layman literacy
What is one hot encoding? In pytoch, there are two ways to turn label into one hot coding
Kubernetes advanced training camp pod Foundation
Jvm-08-garbage collector
Explanation of time complexity and space complexity
Kubernetes带你从头到尾捋一遍
socket. IO build distributed web push server
Using notepad++ to build an arbitrary language development environment
Using TCL (tool command language) to manage Tornado (for VxWorks) can start the project
求字符串函数和长度不受限制的字符串函数的详解
Popular understanding of linear regression (II)