驱动通信:
0环:
1.设备对象
驱动如果想和应用程序进行通讯,需要有设备对象,首先要先创建驱动对象;
NTSTATUS //原型
IoCreateDevice(
_In_ PDRIVER_OBJECT DriverObject,
_In_ ULONG DeviceExtensionSize,
_In_opt_ PUNICODE_STRING DeviceName,
_In_ DEVICE_TYPE DeviceType,
_In_ ULONG DeviceCharacteristics,
_In_ BOOLEAN Exclusive,
PDEVICE_OBJECT *DeviceObject
);
//使用例子:
IoCreateDevice(pDriver,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&pDevice);
2.符号链接
应用层是无法直接通过设备名字访问设备的,需要通过建立符号链接进行访问
NTSTATUS //原型
IoCreateSymbolicLink(
_In_ PUNICODE_STRING SymbolicLinkName,
_In_ PUNICODE_STRING DeviceName
);
//使用例子:
IoCreateSymbolicLink(&SymNameLink,&DeviceName);
注意:符号链接得原理就是记录一个字符串对应到另一个字符串的一种简单结构,所以符号链接的方式并不安全,存在和其他驱动的符号链接发生冲突的情况下
方式1:先进行尝试删除这个符号链接,如果存在就被删除了,如果不存在也无所谓,再创建
方式2:使用GUID的方式来访问设备
3.分发函数
处理三环发送给设备对象的请求的函数,比如:OPEN,CLOSE,DEVICE CONTROL等
#define IRP_MJ_CREATE 0x00
#define IRP_MJ_CREATE_NAMED_PIPE 0x01
#define IRP_MJ_CLOSE 0x02
#define IRP_MJ_READ 0x03
#define IRP_MJ_WRITE 0x04
#define IRP_MJ_QUERY_INFORMATION 0x05
#define IRP_MJ_SET_INFORMATION 0x06
#define IRP_MJ_QUERY_EA 0x07
...
不同的分发函数对应处理不同的请求
NTSTATUS //分发函数原型
DRIVER_DISPATCH (
_In_ struct _DEVICE_OBJECT *DeviceObject,
_Inout_ struct _IRP *Irp
);
需要把分发函数添加给对应的设备对象,可以把所有的Irp接收都用同一个分发函数,在函数内部进行区分,也可以对应不同的分发函数;
//方式1
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriver->MajorFunction[i] = DisPatch;
}
//方式2
pDriver->MajorFunction[IRP_MJ_CREATE] = CreateCallBack;
pDriver->MajorFunction[IRP_MJ_CLOSE ] = CloseCallBack;
4.请求的处理
通过以下函数的函数框架,获取控制码,不同的控制码实现不同的具体的功能请求;
NTSTATUS
CreateCallBack(
_In_ struct _DEVICE_OBJECT* DeviceObject,
_Inout_ struct _IRP* Irp
)
{
ULONG Code = psl->Parameters.DeviceIoControl.IoControlCode;
...
Irp->IoStatus.Information = Ret_len; //返回的输出长度是多少
Irp->IoStatus.Status = status; //请求的返回状态
IoCompleteRequest(Irp, IO_NO_INCREMENT); //结束请求
return STATUS_SUCCESS;
}
5.删除
结束之前,需要删除控制设备和符号。这两项操作最好是在Driver->DriverUnload中进行
IoDeleteDevice(pDriver->DeviceObject); //删除控制设备
IoDeleteSymbolicLink(&SymNameLink); //删除符号链接
3环
1.打开设备
在0环代码实现中,已经介绍过,在三环是无法通过设备名访问设备的,需要通过符号链接名,注意,如果失败了返回值INVALID_HANDLE_VALUE
ret = CreateFile(
SYMBOL_NAME_LINK, //符号链接名
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM,
NULL
);
if(ret == INVALID_HANDLE_VALUE)
{
return FALSE;
}
2.设备控制请求
设备的请求,在系统中只规定了0x1b个,显然这并不能满足请求的种类,这就需要我们自己去定义不同的请求,通过宏CTL_CODE
CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
//注意0-7FF是系统保留的,所以我们只能定义0x7FF以上,且不超出0xFFF的CODE
通过DeviceIoControl把消息进行传输
BOOL
WINAPI
DeviceIoControl(
__in HANDLE hDevice,
__in DWORD dwIoControlCode,
__in_bcount_opt(nInBufferSize) LPVOID lpInBuffer,
__in DWORD nInBufferSize,
__out_bcount_part_opt(nOutBufferSize, *lpBytesReturned) LPVOID lpOutBuffer,
__in DWORD nOutBufferSize,
__out_opt LPDWORD lpBytesReturned,
__inout_opt LPOVERLAPPED lpOverlapped
);