上一篇说的是直接方式的读取设备, 这篇接着说. 其实还有两种方式的, 一种是直接方式读写设备, 这种方式需要创建完设备以后将Flags设置成DO_DIRECT_IO. 这种的话就是Windows内部给做内存映射, 所以相对比缓冲区方式的话就快多了.

款式也是和上一篇一样了, 就是还是模拟写入文件和读取文件的款式, 没有什么太大的区别, 主要的区别是内核这边操作方式不一样了,还多了个MDL, 这个东西Windows驱动开发技术详解也没有说, 寒江独钓也没有说, 我倒. 回头看看其他书. 反正都是这么用, 就先将就着用吧!不过这心里卡主东西, 让我很难受了.回头再看看.

直接上代码吧. 没有撒好说的, 上一篇都说了, 用户态的代码就和上一篇一样了. 主要来看看这个内核态代码!

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
	Windows内核下模拟文件的读写操作, IRP的处理(使用MDL的IO方式) 0环代码
	编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>
#define  DEVICE_NAME	L"\\Device\\DevJoenDevice"
#define  SYS_LINK_NAME	L"\\??\\SysLinkJoenDevice"
#define  MAX_LENGTH	1024

typedef struct tagDEVICEEXT {
	CHAR*		pBuf;
	ULONG		ulCurFileLength;
	PDEVICE_OBJECT	pDeviceObj;
	UNICODE_STRING	USzDeviceName;
	UNICODE_STRING	USzSysLinkName;
}DEVICEEXT, *PDEVICEEXT;
//===========================================================================
//驱动卸载例程
VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) {
	PDEVICEEXT pDriveExt;
	PDEVICE_OBJECT pNextDeviceObj;

	pNextDeviceObj = pDriverObj->DeviceObject;
	while ( pNextDeviceObj != NULL ) {
		pDriveExt = (PDEVICEEXT)pNextDeviceObj->DeviceExtension;

		//删除设备和符号链接
		IoDeleteDevice(pNextDeviceObj);
		IoDeleteSymbolicLink(&pDriveExt->USzSysLinkName);

		KdPrint(( "删除%wZ设备成功!\n", &pDriveExt->USzDeviceName ));

		pNextDeviceObj = pNextDeviceObj->NextDevice;
	}	

}
//===========================================================================
//其他一概不关心的IRP处理
NTSTATUS DispatchRoutin( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return STATUS_SUCCESS;
}
//===========================================================================
//读请求处理例程
NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	ULONG ulReadLength;
	ULONG ulReadOffset;
	ULONG ulMdlLength;
	ULONG ulMdlOffset;
	PVOID ulMdlAddress;
	CHAR* pBuf;
	NTSTATUS Status;
	PDEVICEEXT pDeviceExt;
	PIO_STACK_LOCATION Stack;

	pDeviceExt = (PDEVICEEXT)pDeviceObj->DeviceExtension;
	Stack = IoGetCurrentIrpStackLocation(pIrp);

	//读取长度和偏移
	ulReadOffset = (ULONG)Stack->Parameters.Read.ByteOffset.QuadPart;
	ulReadLength = Stack->Parameters.Read.Length;

	ulMdlAddress = MmGetMdlVirtualAddress( pIrp->MdlAddress );
	ulMdlLength = MmGetMdlByteCount( pIrp->MdlAddress );
	ulMdlOffset = MmGetMdlByteOffset( pIrp->MdlAddress );

	//要读取长度大于最大长度, 返回失败
	if ( ulReadLength + ulReadOffset > MAX_LENGTH ) {
		Status = STATUS_FILE_INVALID;
		ulReadLength = 0;
	}else {
		//获取到那个MDL对应的内核地址, 都是这么用. 回头搞明白到底做了什么?
		pBuf = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
		KdPrint(( "内核下的映射地址%p\n", pBuf ));

		//写会3环那边
                RtlCopyMemory(pBuf, pDeviceExt->pBuf+ulReadOffset,ulReadLength );
		Status = STATUS_SUCCESS;
	}

	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return Status;
}
//===========================================================================
//写请求处理例程
NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	CHAR*		pBuf;
	NTSTATUS	Status;
	ULONG		ulWriteLength;
	ULONG		ulMdlLength;
	ULONG		ulWriteOffset;
	PVOID		ulMdlAddress;
	ULONG		ulMdlOffset;
	PDEVICEEXT	pDeviceExt;
	PIO_STACK_LOCATION Stack;

	pDeviceExt = (PDEVICEEXT)pDeviceObj->DeviceExtension;
	Stack = IoGetCurrentIrpStackLocation(pIrp);
	ulWriteLength = Stack ->Parameters.Write.Length;
	ulWriteOffset = (ULONG)Stack->Parameters.Write.ByteOffset.QuadPart;

	//目前不了解Windows的内存管理, 先这样用着
	ulMdlLength = MmGetMdlByteCount( pIrp->MdlAddress );
	ulMdlOffset = MmGetMdlByteOffset( pIrp->MdlAddress );
	ulMdlAddress = MmGetMdlVirtualAddress( pIrp->MdlAddress );

	//如果要写入的长度达到了最大长度, 返回无效.
        if ( ulWriteOffset + ulWriteLength > MAX_LENGTH ) {
                Status = STATUS_FILE_INVALID;
                ulWriteLength = 0;
	}

	//MDL的长度应该和读取的长度相等. 否则就有问题了
	if ( ulMdlLength != ulWriteLength ) {
		pIrp->IoStatus.Information= 0;
		Status = STATUS_UNSUCCESSFUL;

	}else {
		//获取到那个MDL对应的内核地址, 都是这么用. 回头搞明白到底做了什么?
		pBuf = MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
		KdPrint(( "内核下的映射地址%p\n", pBuf ));

		//将3环那边的数据存储在缓冲区中
                RtlCopyMemory(pDeviceExt->pBuf+ulWriteOffset,pBuf,ulWriteLength );

		if ( ulWriteLength + ulWriteOffset > pDeviceExt->ulCurFileLength ) {
			pDeviceExt->ulCurFileLength = ulWriteLength + ulWriteOffset;
		}

		pIrp->IoStatus.Information = ulWriteLength;
		Status = STATUS_SUCCESS;
	}
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return Status;
}
//===========================================================================
//驱动入口
#pragma code_seg( "INIT" )
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
	ULONG i;
	NTSTATUS Status;
	PDEVICEEXT pDeviceExt;
	PDEVICE_OBJECT pDeviceObj;
	UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYS_LINK_NAME );
	UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME );

	//创建设备
	Status = IoCreateDevice( pDriverObj, sizeof(DEVICEEXT),&USzDeviceName,
		FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObj );
	if ( !NT_SUCCESS(Status) ) {
		KdPrint(( "创建设备失败!\n" ));
		return Status;
	}

	//创建符号链接
	Status = IoCreateSymbolicLink(&USzSysLinkName, &USzDeviceName );
	if ( !NT_SUCCESS(Status) ) {
		KdPrint(( "创建符号链接失败!\n" ));
		IoDeleteDevice( pDeviceObj );
		return Status;
	}

	//直接缓冲区方式
	pDeviceObj->Flags |= DO_DIRECT_IO;
	pDeviceExt = (PDEVICEEXT)pDeviceObj->DeviceExtension;
	pDeviceExt->pDeviceObj = pDeviceObj;
	pDeviceExt->USzDeviceName = USzDeviceName;
	pDeviceExt->USzSysLinkName = USzSysLinkName;
	pDeviceExt->pBuf = ExAllocatePool(PagedPool, MAX_LENGTH );
	RtlZeroMemory(pDeviceExt->pBuf, MAX_LENGTH );

	//设置分发函数和卸载函数
	for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
		pDriverObj->MajorFunction[i] = &DispatchRoutin;
	}
	pDriverObj->MajorFunction[IRP_MJ_READ] = &DispatchRead;
	pDriverObj->MajorFunction[IRP_MJ_WRITE]= &DispatchWrite;
	pDriverObj->DriverUnload = &DriverUnLoad;

	return Status;
}