欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]浅谈那些年来我们用过的设备操作

[原创]浅谈那些年来我们用过的设备操作


驱动所创建的设备一般有三种操作方式:缓冲区方式DO_BUFFERED_IO,直接方式DO_DIRECT_IO,其他方式
1.缓冲区
缓冲区地址属于内核地址,因为要是在用户层的话,会导致进程的切换问题最终发生严重的错误。
(1.)利用缓冲区操作必须先在底层申请一块内存地址来存放这些数据;
(2.)我们关心的是如何得到写入的大小和数据,File_Size=stack->Parameters.Read.Length;
.....
详细请看代码:[IRP_MJ_READ]

NTSTATUS Writea(IN PDEVICE_OBJECT pDevice,

			   IN PIRP pIrp)

{

	NTSTATUS Status=STATUS_SUCCESS;

	PDEVICE_EXTENSION PDeviN=(PDEVICE_EXTENSION)pDevice->DeviceExtension;

	PIO_STACK_LOCATION stack=IoGetCurrentIrpStackLocation(pIrp);

	ULONG WriteLenth=stack->Parameters.Write.Length;

	ULONG WriteOffset=stack->Parameters.Write.ByteOffset.QuadPart;

	if (WriteLenth+WriteOffset>1024)  //1024是我们分配的内存大小,超过了你很可能就挂彩了

	{

		Status=STATUS_FILE_INVALID;

		WriteLenth=0;

	}

	else

	{

		KdPrint(("write buffer 0x%x\n",PDeviN->buffer));

	KdPrint(("write Ox%x\n",WriteOffset));

	KdPrint(("write Ox%x\n",WriteLenth));

		memcpy(PDeviN->buffer+WriteOffset,pIrp->AssociatedIrp.SystemBuffer,WriteLenth);

		Status=STATUS_SUCCESS;

		if (WriteLenth+WriteOffset>PDeviN->file_length)

		{

PDeviN->file_length=WriteLenth+WriteOffset;

		}

	}

	pIrp->IoStatus.Status=Status;

	pIrp->IoStatus.Information=WriteLenth;

	IoCompleteRequest(pIrp,IO_NO_INCREMENT);

	return Status;

}

(3.)
NTSTATUS Reada(IN PDEVICE_OBJECT pDevObj,

			   IN PIRP pIrp)

{	

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

NTSTATUS status = STATUS_SUCCESS;

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

ULONG ReadLength = stack->Parameters.Read.Length;

ULONG ReadOffset = (ULONG)stack->Parameters.Read.ByteOffset.QuadPart;

if (ReadOffset+ReadLength>1024)

{

	status = STATUS_FILE_INVALID;

	ReadLength = 0;

}else

{

	KdPrint(("Read buffer 0x%x\n",pDevExt->buffer));

	KdPrint(("Read WriteOffset Ox%x\n",ReadOffset));

	KdPrint(("Read WriteLenth Ox%x\n",ReadLength));

    memcpy(pIrp->AssociatedIrp.SystemBuffer,pDevExt->buffer+ReadOffset,ReadLength);

	status = STATUS_SUCCESS;

}

     pIrp->IoStatus.Status=status;

	 pIrp->IoStatus.Information=ReadLength;

	 IoCompleteRequest(pIrp,IO_NO_INCREMENT);

   return status;

}

2.直接设备操作DO_DIRECT_IO
(1.)在于此时的flags已经不是DO_BUFFERED_IO而是DO_DIRECT_IO
(2.)区别在于内核不需要在分配内存作为r3存储数据,这是用用户层的地址被锁定操作系统用(MDL)内存描述符来记录这段地址。
(3.)这段被MDL记录的地址包晗了 文件读写请求大小(Mdl_lenth)  相对偏移地址(Mdl_offset)
第一页地址(StartVa).那么这段虚拟内存地址应该就是Startva+Mdl_offset。
DDK中已经有宏来方便得到这些数值:
#define MmGetMdlVirtualAddress(Mdl)                                     \

    ((PVOID) ((PCHAR) ((Mdl)->StartVa) + (Mdl)->ByteOffset))

//++

//

// ULONG

// MmGetMdlByteCount (

//     __in PMDL Mdl

//     )

//

// Routine Description:

//

//     The MmGetMdlByteCount returns the length in bytes of the buffer

//     described by the Mdl.

//

// Arguments:

//

//     Mdl - Pointer to an MDL.

//

// Return Value:

//

//     Returns the byte count of the buffer described by the Mdl

//

//--

#define MmGetMdlByteCount(Mdl)  ((Mdl)->ByteCount)

//++

//

// ULONG

// MmGetMdlByteOffset (

//     __in PMDL Mdl

//     )

//

// Routine Description:

//

//     The MmGetMdlByteOffset returns the byte offset within the page

//     of the buffer described by the Mdl.

//

// Arguments:

//

//     Mdl - Pointer to an MDL.

//

// Return Value:

//

//     Returns the byte offset within the page of the buffer described by the Mdl

//

//--

#define MmGetMdlByteOffset(Mdl)  ((Mdl)->ByteOffset)

//++

//

// PVOID

// MmGetMdlStartVa (

//     __in PMDL Mdl

//     )

//

// Routine Description:

//

//     The MmGetMdlBaseVa returns the virtual address of the buffer

//     described by the Mdl rounded down to the nearest page.

//

// Arguments:

//

//     Mdl - Pointer to an MDL.

//

// Return Value:

//

//     Returns the returns the starting virtual address of the MDL.

//

//

//--

#define MmGetMdlBaseVa(Mdl)  ((Mdl)->StartVa)

(4.)kernel_Address(映射后的内核地址,用来写数据和读数据用的)
通过        
PVOID Kernel_Address=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
来实现
(5.)具体代码请看下面:
NTSTATUS Writea(IN PDEVICE_OBJECT pDevice,

				IN PIRP pIrp)

{

	KdPrint(("WIRTE ROUNTION"));

	NTSTATUS Status=STATUS_SUCCESS;

	PDEVICE_EXTENSION PDeviN=(PDEVICE_EXTENSION)pDevice->DeviceExtension;

	PIO_STACK_LOCATION stack=IoGetCurrentIrpStackLocation(pIrp);

	ULONG ulWriteLeng=stack->Parameters.Write.Length;

	ULONG Mdl_offset=MmGetMdlByteOffset(pIrp->MdlAddress);

	PVOID Mdl_address=MmGetMdlVirtualAddress(pIrp->MdlAddress);

	ULONG Mdl_lenth=MmGetMdlByteCount(pIrp->MdlAddress);

	if (Mdl_lenth!=ulWriteLeng)

	{

		Status=STATUS_UNSUCCESSFUL;

		pIrp->IoStatus.Information=0;

	}

	else

	{

		KdPrint(("write buffer 0x%x\n",PDeviN->buffer));

		KdPrint(("write Ox%x\n",Mdl_offset));

		KdPrint(("write Ox%x\n",Mdl_lenth));

		PVOID Kernel_Address=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);

               Status=STATUS_SUCCESS;

		pIrp->IoStatus.Information=Mdl_lenth;

	}

	pIrp->IoStatus.Status=Status;

	IoCompleteRequest(pIrp,IO_NO_INCREMENT);

	return Status;

}

NTSTATUS Reada(IN PDEVICE_OBJECT pDevObj,

			   IN PIRP pIrp)

{	

	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

	NTSTATUS status = STATUS_SUCCESS;

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

	ULONG ulReadLength = stack->Parameters.Read.Length;

ULONG Mdl_lenth=MmGetMdlByteCount(pIrp->MdlAddress);

PVOID Mdl_Address=MmGetMdlVirtualAddress(pIrp->MdlAddress);

ULONG Mdl_offset=MmGetMdlByteOffset(pIrp->MdlAddress);

if (Mdl_lenth!=ulReadLength)

{

	pIrp->IoStatus.Information=0;

	status=STATUS_UNSUCCESSFUL;

} 

else

{

	PVOID Kernel_Address=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);

	KdPrint(("the kernel address is 0x%x\n",Kernel_Address));

	pIrp->IoStatus.Information=ulReadLength;

}

	pIrp->IoStatus.Status=status;

	IoCompleteRequest(pIrp,IO_NO_INCREMENT);

	return status;

}


3.()
下面是R3代码:
#include <windows.h>

#include <stdio.h>

int main()

{

	HANDLE hDevice = 

		CreateFile("\\\\.\\KANXUE",

					GENERIC_READ | GENERIC_WRITE,

					0,		

					NULL,	

					OPEN_EXISTING,

					FILE_ATTRIBUTE_NORMAL,

					NULL );	

	if (hDevice == INVALID_HANDLE_VALUE)

	{

		return 1;

	}

	UCHAR buffer[10];

memset(buffer,0xCC,8);

	UCHAR F[10];

	ULONG ulRead;

	ULONG ulWrite;

	BOOL bRet;

	bRet = WriteFile(hDevice,buffer,8,&ulWrite,NULL);

	if (bRet)

	{

		printf("写入了 %d 字节\n",ulWrite);

	}

	bRet = ReadFile(hDevice,F,8,&ulRead,NULL);

	if (bRet)

	{

		printf("读出 %d 字节:",ulRead);

		for (int i=0;i<(int)ulRead;i++)

		{

			//printf("%02X  ",buffer[i]);

		}

		printf("%s  ",F);

		printf("\n");

	}

	getchar();

	CloseHandle(hDevice);

	return 0;

}

效果图

上传的附件 buffer.zip
QQ截图20140121121014.jpg
DI.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功