IRP是Windows内核中的一种非常重要的数据结构。上层应用程序与底层驱动程序通信时,应用程序会发出I/O请求,操作系统将相应的I/O请求转换成相应的IRP,不同的IRP会根据类型被分派到不同的派遣例程中进行处理。
irp相当于R3下的消息,应用程序对驱动程序进行操作的时候会发出相应的消息,驱动程序根据这些消息做出相应的操作。这些操作通过我们自己编写的派遣函数来决定执行什么样的操作。
当应用层调用 ReadFile WriteFile CreateFile CloseHandle
等WINAPI 函数 则会产生对应的IRP类型,这些IRP 也就是 IRP_MJ_CREATE IRP_MJ_WRITE IRP_MJ_READ IRP_MJ_CLOSE
并且传送到驱动的中的派遣函数中。
另外 内核中的 I/O
处理函数也会产生IRP,所以可见IRP并不完全是由应用层产生的。比如内核中的 Zw系列开头的文件操作 一样会产生IRP。
IRP类型 | 来源 |
---|---|
IRP_MJ_CREATE | CreateFile/ZwCreateFile |
IRP_MJ_READ | ReadFile/ZwReadFile |
IRP_MJ_WRITE | WriteFile/ZwWriteFile |
IRP_MJ_CLOSE | CloseHandle/ZwClose |
... | ... |
... | ... |
程序流程:
1.创建设备与符号链接
2.为不同的IRP类型设置派遣函数
3.编写派遣函数来处理收到不懂类型的IRP的不同操作
4.在卸载函数中删除设备与符号链接
设备对象的通信方式
1.基于缓存方式(DO_BUFFERED_IO):
写入:R0把R3缓冲区的数据复制一份到R0缓冲区里面,写出:R0把数据写入到R3的缓冲区里面
2.直接读写方式(DO_DIRECT_IO):
R3和R0访问同一块物理页
3.两者皆不方式(DO_FORCE_NEITHER_IO):
写入:R0直接读取R3的缓冲区,写出:R0直接写入R3的缓冲区
<直接读写方式> 和 <两者皆不方式>很类似,都是直接访问R3的内存地址,但<直接读写方式>有内存映射机制开销比<两者皆不方式>大,然而<基于缓存方式>最安全。
驱动代码:
#include <ntddk.h>
#define DEVICE_NAME L"\\device\\MyDricer1" //设备对象名称
#define LINK_NAME L"\\dosdevices\\Goose" //符号链接名称
VOID UnDirver(PDRIVER_OBJECT pDriverObj)
{
UNICODE_STRING uLinkName = RTL_CONSTANT_STRING(LINK_NAME);//初始化符号链接名称
IoDeleteSymbolicLink(&uLinkName);//删除符号链接
IoDeleteDevice(pDriverObj->DeviceObject);//删除设备对象
DbgPrint("Driver Unloaded.\n");
}
NTSTATUS MyMajor(PDEVICE_OBJECT Device, PIRP irp)
{
irp->IoStatus.Status = STATUS_SUCCESS;//设置irp处理成功
irp->IoStatus.Information = 0;//设置返回的字节数
IoCompleteRequest(irp, IO_NO_INCREMENT);//结束irp处理流程
DbgPrint("MyMajor");//打印测试
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
pDriverObj->DriverUnload = UnDirver;
UNICODE_STRING uDeviceName = RTL_CONSTANT_STRING(DEVICE_NAME);//初始化设备名称
UNICODE_STRING uLinkName = RTL_CONSTANT_STRING(LINK_NAME);//初始化符号链接名称
PDEVICE_OBJECT pDeviceObject = NULL;
NTSTATUS ntStatus = IoCreateDevice(pDriverObj, 0, &uDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObject);//创建一个设备对象
if (ntStatus != STATUS_SUCCESS)
{
DbgPrint("IoCreateDevice failed:%x\n", ntStatus);
return ntStatus;
}
pDeviceObject->Flags |= DO_BUFFERED_IO;//设置设备对象的通信方式:1.基于缓存方式 2.直接读写方式 3.两者皆不方式
ntStatus = IoCreateSymbolicLink(&uLinkName, &uDeviceName);//把设备对象和链接名称进行绑定,R3可以通过链接名称访问
if (ntStatus != STATUS_SUCCESS)
{
IoDeleteDevice(pDeviceObject);//删除设备对象
DbgPrint("IoCreateSymbolicLink failed:%x\n", ntStatus);
return ntStatus;
}
//驱动对象的所有irp回调函数,设置成我的回调函数
for (size_t i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
{
pDriverObj->MajorFunction[i] = MyMajor;
}
return STATUS_SUCCESS;
}
应用代码:
#include <iostream>
#include <windows.h>
#define LINK_NAME L"\\\\.\\Goose" //符号链接名称
int main()
{
HANDLE hRet = CreateFile(LINK_NAME, GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hRet == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed:%x\n", GetLastError());
system("pause");
return 0;
}
DWORD dwRetSize;
WriteFile(hRet, L"123", 8, &dwRetSize, NULL);
printf("收到数据大小:%d\n", dwRetSize);
system("pause");
return 0;
}