今天来了解一下IRP模块。

IRP

IRP是输入输出请求包(I/O Request Package)的简称

常见的事件有以下几种:

  • IRP_MJ_CREATE:请求一个句柄 CreateFile
  • IRP_MJ_CLOSE:关闭句柄 CloseHandle
  • IRP_MJ_READ:从设备得到数据ReadFile
  • IRP_MJ_WRITE:传送数据到设备 WriteFile
  • IRP_MJ_DEVICE_CONTROL:控制操作利用IOCTL宏 DeviceIOControl

代码

基本框架

这里注册这个 IRP 事件跟注册卸载驱动函数差不多,代码如下:

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
#include<ntifs.h>
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)

NTSTATUS DeviceIrpCtl(PDEVICE_OBJECT driver, PIRP pirp) {
kprintf(("Line %d:xia0ji233: enter IRP Function\n"), __LINE__);
PIO_STACK_LOCATION irpStackL;
ULONG CtlCode;
ULONG InputBuffLength;
irpStackL = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的参数

switch (irpStackL->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL: {
kprintf(("Line %d:xia0ji233: ring3 calls DEVICE CONTROL\n"), __LINE__);
break;
}
case IRP_MJ_CREATE: {
kprintf(("Line %d:xia0ji233: ring3 calls CREATE\n"), __LINE__);
break;
}
case IRP_MJ_CLOSE: {
kprintf(("Line %d:xia0ji233: ring3 calls CLOSE\n"), __LINE__);
break;
}
default:
break;
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 4;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
kprintf(("Line %d:xia0ji233: leave IRP Function\n"), __LINE__);
return STATUS_SUCCESS;
}
void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: unload success\n"),__LINE__);
}
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
){
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceIrpCtl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceIrpCtl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIrpCtl;

kprintf(("RegistryPath = %S\n"), RegistryPath->Buffer);
kprintf(("Line %d:xia0ji233: work success\n"), __LINE__);

return 0;
}

但是这样生成的 sys 被加载之后并不会调用到 IRP 的这个函数,需要 ring3 层去调用对应的函数来触发。

这里可以用一个空宏来忽略局部变量未使用的错误:UNREFERENCED_PARAMETER(p)。

这里需要理解一下两个概念:

  • 驱动设备(DEVICE_OBJECT):可以是硬件,也可以是软件。
  • 驱动对象(DRIVER_OBJECT):用于创建驱动设备对象的,用于创建多个驱动设备。

反正主要记一下,这俩东西是不一样的。

创建设备代码和符号链接

设备是有名字的,名字遵循变量命名规则。因为在 UNICODE 字符集的环境下,我们先定义一个 UNICODE 字符串,并赋值:

1
2
UNICODE_STRING MyDriver;
RtlInitUnicodeString(&MyDriver, L"\\DEVICE\\xia0ji233");

然后创建设备:

1
2
3
4
5
6
7
8
9
10
11
12
NTSTATUS status;
PDEVICE_OBJECT device=NULL;
RtlInitUnicodeString(&MyDriver, L"\\DEVICE\\xia0ji233");
status = IoCreateDevice(
driver,
sizeof(driver->DeviceExtension),
&MyDriver,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&device
);

此时,创建的对象指针返回到了 device 当中,下一步应该创建符号链接,这里可以简单判断一下是否创建成功。

成功之后,可以创建符号链接去,这里的符号链接是给 ring3 的用户层去使用的,而这里创建出来的 Device 只能在内核层使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (status == STATUS_SUCCESS) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, L"\\??\\xia0ji2333");
status = IoCreateSymbolicLink(&Sym, &MyDriver);
if (status == STATUS_SUCCESS) {
kprintf(("Line %d:xia0ji233: symbol linked success\n"), __LINE__);
}
else {
kprintf(("Line %d:xia0ji233: symbol linked failed status=%x\n"), __LINE__, status);
}
}
else {
kprintf(("Line %d:xia0ji233: create device fail status=%x\n"), __LINE__, status);
}

这里需要注意,创建的符号链接和设备名称不能一样,虽然看别人好像能一样,但是自己一样的话报错了就。

删除设备代码和符号链接

然后再把删除设备和删除符号的一些代码写好,在 unload 例程当中去调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
DeleteDevice(pDriver);
}
void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
//删除符号链接
UNICODE_STRING Sym;//符号链接名字
RtlInitUnicodeString(&Sym, L"\\??\\xia0ji2333");//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);//删除设备对象
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}

三环应用程序

直接像这样,使用 CreateFile 去创建,但是似乎有点问题。

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <Windows.h>
#define SYMBOL L"\\\\??\\\\xia0ji2333"
int main()
{
HANDLE DriverHandle = CreateFile(SYMBOL, 0, 0, 0, 0, 0, 0);
printf("handle=%x\n", DriverHandle);
getchar();
}

驱动总代码

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
#include<ntifs.h>
#include "main.h"
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)

NTSTATUS CreateDevice(PDEVICE_OBJECT driver) {
NTSTATUS status;
UNICODE_STRING MyDriver;
PDEVICE_OBJECT device = NULL;
RtlInitUnicodeString(&MyDriver, L"\\DEVICE\\xia0ji233");
status = IoCreateDevice(
driver,
sizeof(driver->DeviceExtension),
&MyDriver,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&device
);
if (status == STATUS_SUCCESS) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);
status = IoCreateSymbolicLink(&Sym, &MyDriver);
if (status == STATUS_SUCCESS) {
kprintf(("Line %d:xia0ji233: symbol linked success\n"), __LINE__);
}
else {
kprintf(("Line %d:xia0ji233: symbol linked failed status=%x\n"), __LINE__, status);
}
}
else {
kprintf(("Line %d:xia0ji233: create device fail status=%x\n"), __LINE__, status);
}
}
NTSTATUS DeviceIrpCtl(PDEVICE_OBJECT driver, PIRP pirp) {
kprintf(("Line %d:xia0ji233: enter IRP Function\n"), __LINE__);
PIO_STACK_LOCATION irpStackL;
ULONG CtlCode;
ULONG InputBuffLength;
irpStackL = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的参数
switch (irpStackL->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL: {
kprintf(("Line %d:xia0ji233: ring3 calls DEVICE CONTROL\n"), __LINE__);
break;
}
case IRP_MJ_CREATE: {
kprintf(("Line %d:xia0ji233: ring3 calls CREATE\n"), __LINE__);
break;
}
case IRP_MJ_CLOSE: {
kprintf(("Line %d:xia0ji233: ring3 calls CLOSE\n"), __LINE__);
break;
}
default:
break;
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 4;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
kprintf(("Line %d:xia0ji233: leave IRP Function\n"), __LINE__);
return STATUS_SUCCESS;

}

void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
DeleteDevice(pDriver);
}

NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
){
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceIrpCtl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceIrpCtl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIrpCtl;
CreateDevice(DriverObject);
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"),__LINE__,RegistryPath->Buffer);
kprintf(("Line %d:xia0ji233: work success\n"), __LINE__);

return 0;
}

void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
//删除符号链接
UNICODE_STRING Sym;//符号链接名字
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);//删除设备对象
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}

细节明天再看看吧,来看看基本的运行情况: