消息是从窗口,发给窗口 。在0环就需要一个设备对象来接收消息
IRP列表
设置交互数据的方式
缓冲区方式读写 DO_BUFFERED_IO
这种通信方式是把三环的buffer拷贝到0环,然后0环再去读 适合数据较少时的情况
在IRP_MJ_DEVICE_CONTROL IRP中
如果是在IRP_MJ_READ中:
输入/出缓冲区:Irp->AssociatedIrp.SystemBuffer
输入缓冲区长度:stack->Parameters.Read.Length
直接读写方式DO_DIRECT_IO
直接读写,就是把3环和0环的buffer映射到同一个物理页,然后把这个物理页锁起来。比较浪费内存,适合数据量大的情况
涉及到MDL的操作,都尽量使用ddk提供的函数.而不要直接去操作相应的字段.
获取输入缓冲区 InputBuffer=pIrp->UserBuffer ;
获取输入缓冲区长度 InputLength=stack->Parameters.Read.Length;
获取输出缓冲区地址: OutBuffer =MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
获取输出缓冲区长度: length=stack->Parameters.DeviceIoControl.OutputBufferLength;
第三种方式:0环直接到3环读取数据,不太靠谱,如果这时进程被切走,读取的数据就会不正确。不推荐使用。
0环代码
#include<ntddk.h>
#include<ntstatus.h>
#define DEVICE_NAME L"\\Device\\MyDevice"
#define SYMBOLICLINE_NAME L"\\??\\MyTestDriver" //ring3用CreateFile打开设备时,用"\\\\.\\MyTestDriver"//相当于起的别名
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
//实现卸载函数和派遣函数
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
UNICODE_STRING SymbolicLinkName = { 0 };
RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);
IoDeleteDevice(pDriver->DeviceObject);
IoDeleteSymbolicLink(&SymbolicLinkName);
}
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
DbgPrint("DispatchCreate ... \n");
pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
PIO_STACK_LOCATION pIrpStack;//定义一个指向IO_STACK_LOCATION结构体的指针
PVOID pIoBuffer;
ULONG Length;
DbgPrint("DispatchRead ... \n");
//从Irp头部获取buffer地址
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
//从当前Irp栈中获取buffer的长度
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//根据从ring3发来的
//获取buffer长度 Parameters里面是一个联合体 Read Write DeviceIoControl
Length = pIrpStack->Parameters.Read.Length;
pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IrpWriteProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
PIO_STACK_LOCATION pIrpStack;//定义一个指向IO_STACK_LOCATION结构体的指针
PVOID pIoBuffer;
ULONG Length;
DbgPrint("DispatchWrite ... \n");
//从Irp头部获取buffer地址
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
//从当前Irp栈中获取buffer的长度
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//根据从ring3发来的
//获取buffer长度 Parameters里面是一个联合体 Read Write DeviceIoControl
Length = pIrpStack->Parameters.Write.Length;
DbgPrint("DispatchWrite ... \n");
pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IrpDefaultProc(PDEVICE_OBJECT pdriver, PIRP pIrp)
{
DbgPrint("DispatchClose ... \n");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IrpDeviceContrlProc(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIrpStack;//定义一个指向IO_STACK_LOCATION结构体的指针
ULONG uIoControCode;
PVOID pIoBuffer;
ULONG uInLength;
ULONG uOutLength;
ULONG uRead;
//获取缓冲区地址(输入和输出的缓冲区都是一个)
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
//从当前Irp中获取数据
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//根据从ring3发来的
//获取控制码 Parameters里面是一个联合体 Read Write DeviceIoControl
uIoControCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
//ring 3发送数据的长度
uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
//ring 0 发送数据的长度
uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (uIoControCode)
{
case OPER1:
{
DbgPrint("IrpDeviceContrlProc -> OPER1 ...\n");
pIrp->IoStatus.Information = 0;
break;
}
case OPER2:
{
DbgPrint("IrpDeviceContrlProc -> OPER2 接受字节数:%x \n", uInLength);
DbgPrint("IrpDeviceContrlProc -> OPER2 返回字节数:%x \n", uOutLength);
//读取3环传过来的数据
RtlCopyMemory(&uRead, pIoBuffer, 4);
DbgPrint("IrpDeviceContrlProc -> OPER2 ...%x \n", uRead);
//把数据传回给3环
*(ULONG*)pIoBuffer = 0x1314520;
//set Status
//设置给3环返回数据的字节数
pIrp->IoStatus.Information = 4;
break;
}
}
//设置返回状态
DbgPrint("DispatchDeviceControl ... \n");
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING reg_path)
{
NTSTATUS Status = 0;
PDEVICE_OBJECT DeviceObj = NULL;
UNICODE_STRING DeviceName;
UNICODE_STRING SymbolicLinkName;
//设置派遣函数和卸载函数
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = IrpDefaultProc;
}
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceContrlProc;
DriverObject->DriverUnload = DriverUnload;
//创建设备名称
RtlInitUnicodeString(&DeviceName, DEVICE_NAME);
//创建设备 让三环的API能够找到,才能实现通信
Status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObj);
if (Status != STATUS_SUCCESS)
{
DbgPrint("创建设备失败! Status=%x\r\n", Status);
return Status;
}
//设置交互数据方式
DeviceObj->Flags |= DO_BUFFERED_IO;
//创建符号链接名称,就是给该设备在三环起个能用的别名
RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);
//创建符号链接
Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
if (!NT_SUCCESS(Status))
{
DbgPrint("创建符号链接失败!\r\n");
IoDeleteDevice(DeviceObj);
return Status;
}
//去掉正在初始化标志,驱动设备开始接收Irp消息
DeviceObj->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
3环代码
#include<windows.h>
#include<winioctl.h>
#include<stdio.h>
#define IN_BUFFER_MAXLENGTH 0x10
#define OUT_BUFFER_MAXLENGTH 0x10
//宏定义之获取一个32位的宏控制码 参数:设备类型(鼠标,键盘...Unkonwn);0x000-0x7FF保留,0x800-0xfff随便填一个;数据交互类型(缓冲区,IO,其他);对这个设备的权限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define SYMBOLICLINK_NAME L"\\\\.\\MyTestDriver"
HANDLE g_hDevice; //全局驱动句柄
//打开驱动服务句柄
//3环链接名:\\\\.\\AABB
BOOL Open(LPCWCHAR pLinkName)
{
//在3环获取设备句柄
TCHAR szBuffer[10] = { 0 };
//CreateFile 打开的是内核的设备对象
g_hDevice = CreateFile(pLinkName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (g_hDevice != INVALID_HANDLE_VALUE)
return TRUE;
else
return FALSE;
}
int main(int argc, char* argv[])
{
DWORD dwInBuffer = 0x12345678;
DWORD szOutBuffer = 0;
DWORD ByteReturned = 0;
//1.通过符号链接,打开设备
if (!Open(SYMBOLICLINK_NAME))
{
printf("设备对象打开失败!!!");
getchar();
return 0;
}
//2.测试通信
DeviceIoControl(g_hDevice, OPER2, &dwInBuffer, IN_BUFFER_MAXLENGTH, &szOutBuffer, OUT_BUFFER_MAXLENGTH, &ByteReturned, NULL);
printf("%x %x\n", szOutBuffer, ByteReturned);
//3.关闭设备
CloseHandle(g_hDevice);
getchar();
return 0;
}
练习:
做一个界面,选中一项时,右键强制结束进程。