0环和3环通信

消息是从窗口,发给窗口 。在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;
}

练习:

做一个界面,选中一项时,右键强制结束进程。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值