/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
函数说明:这个是分发函数的定义、分发函数的参数和返回值都是一样的!
/
/
参数一:PDEVICE_OBJECT pObject 这个指的是设备对象,创建设备对象主要用来接收R3的IRP数据
/
/
参数二:PIRP pIrp 应用层传递过来的IRP
/
/
这个IRP指针就是应用层传递过来的数据被IO管理器组织好的一个数据,
/
/
这个IRP负责发给设备对象。这个设备对象接受之后会调用这个分发函数来处理他!
/
/
返回值:返回值是STATUS_SUCCESS、在内核层返回STATUS_SUCCESS也就是
0
就成功,在应用层返回
0
则失败!和内核层是倒过来!
/
/
备注:
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
NTSTATUS DispatchWrite(PDEVICE_OBJECT pObject, PIRP pIrp)
{
/
/
定义应用层发过来的缓存区指针
PVOID pWriteBuffer
=
NULL;
/
/
定义应用层发送过来的长度
ULONG uWriteLength
=
0
;
/
/
定义IRP的当前栈
PIO_STACK_LOCATION pStack;
/
/
定义分配的内核分页内存
PVOID pBuffer
=
NULL;
/
/
分析WriteFile函数
/
/
参数一:一个文件句柄
/
/
参数二:这个
buffer
就存放应用层的文件数据!
/
/
参数三:写入的字节数大小
/
/
参数四:实际写入的字节数 与pIrp
-
>IoStatus.Infomation对应
/
/
参数五:异步操作
/
/
通过IRP拿到在内核缓存区的地址
pBuffer
=
pIrp
-
>AssociatedIrp.SystemBuffer;
/
/
获取当前的堆栈
pStack
=
IoGetCurrentIrpStackLocation(pIrp);
/
/
Parameters是一个联合体、如果是写则Parameters.Write、如果是Read则Parameters.Read 依次类推
uWriteLength
=
pStack
-
>Parameters.Write.Length;
/
/
在内核中分配分配一块内存
/
/
分页内存(PagedPool):指的是分配一块分页内存!分页内存是会一直锁住不会被分配出去的内存!
/
/
注意:分页内存只能在IRQL:PASSIVE模式下使用,分发函数的IRQL都是PASSIVE模式(无中断级别)!
/
/
IRQL: 中断请求级别。
/
/
PASSIVE : 无中断级别。
/
/
非分页内存(NoPagedPool):是在任何场景下都可以使用的内存。可以在内存中任意位置使用,访问非分页内存不会发生缺页中断!
/
/
大小上非分页内存与分页内存的区别:非分页内存 < 分页内存、所以一般使用分页内存、一般的非分页内存为一两百兆
pBuffer
=
ExAllocatePoolWithTag(PagedPool, uWriteLength,
'TSET'
);
/
/
/
/
这里是’TSET’是一个标志,不是一个字符串!则这里是一个四个字节的整数,那么在内存中存放的位置是小端方式,所以在内存中所看到的是’TEST’!
if
(pBuffer
=
NULL)
{
/
/
STATUS_SUCCESS:标志是成功!
/
/
STATUS_UNSUCCESSFUL : 标志访问拒接!
/
/
STATUS_ACCESS_DENIED : 主防中所用到的标志!
/
/
STATUS_INSUFFICIENT_RESOURCE : 表示资源(内存)不足!
/
/
分配失败则返回内存空间不足
pIrp
-
>IoStatus.Status
=
STATUS_INSUFFICIENT_RESOURCES;
/
/
附加信息为
0
pIrp
-
>IoStatus.Information
=
0
;
/
/
结束当前的IRP
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
/
/
给IO管理器返回当前的资源不足
return
STATUS_INSUFFICIENT_RESOURCES;
}
/
/
分配成功则把这块内存清
0
memset(pBuffer,
0
, uWriteLength);
/
/
拷贝、长度是应用层传递过来的长度。
RtlCopyMemory(pBuffer, pWriteBuffer,uWriteLength);
/
/
释放在堆申请的内存,在堆中的内存必须得需要释放!
ExFreePool(pBuffer);
/
/
将这个设置成NULL、避免其他函数错误了操作了这块堆栈空间
pBuffer
=
NULL;
/
/
设置IRP的状态为成功,终止IRP,然后返回成功!
pIrp
-
>IoStatus.Status
=
STATUS_SUCCESS;
/
/
返回实际写入的大小就是应用层传递过来的大小
pIrp
-
>IoStatus.Information
=
uWriteLength;
/
/
给IO管理器返回一个成功标志
return
STATUS_SUCCESS;
}