今天来了解一下 R3 与 R0 通信。

应用程序与内核交互

打开设备事件

也是解决了昨天 3 环应用程序与内核通信的问题,我们应该用以下代码创建设备:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <Windows.h>
#define SYMBOL L"\\??\\xia0ji2333"
int main()
{
HANDLE DriverHandle = CreateFile(SYMBOL, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
printf("error=%x\n", GetLastError());
printf("handle=%x\n", DriverHandle);
getchar();
}

驱动加载成功之后,直接运行:

发现成功调用到我们指定的 IRP 的回调函数。

如果驱动中存在打开的设备,此时卸载驱动是无法卸载成功的。

写测试

主要函数是使用 DeviceIoControl 函数,虽然有很多参数,但是主要把控制码这个参数解决了,其它的其实都好说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#define WriteCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED, FILE_ANY_ACCESS)
void Wtest() {
DWORD dwRetSize = 0;//返回字节数
char *inBuf = (char *)malloc(0x20);
char *OutBuf = (char *)malloc(0x20);
printf("Your message>");
scanf("%30s", inBuf);

DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
WriteCode,//控制码 CTL_CODE
inBuf,//输入缓冲区指针
strlen(inBuf)+1,//输入缓冲区大小
OutBuf,//返回缓冲区
20,//返回缓冲区大小
&dwRetSize,//返回字节数
NULL
);
printf("control code=%x\n", WriteCode);
}

把宏的 0x803 改成 0x804 是对应的读控制,改成 0x805 是读写控制码,对应的,我们在驱动的那一层稍微修改一下,在 IRP_MJ_DEVICE_CONTROL 的分支中,取出我们输入的字符串并打印出来。

1
2
3
4
5
6
7
case IRP_MJ_DEVICE_CONTROL: {
UINT32 code = irpStackL->Parameters.DeviceIoControl.IoControlCode;
char * buffer = (char *)pirp->AssociatedIrp.SystemBuffer;
kprintf(("Line %d:xia0ji233: ring3 calls DEVICE CONTROL,control code=%x\n"), __LINE__,code);
kprintf(("Line %d:xia0ji233: Get Message:%s\n"), __LINE__, buffer);
break;
}

运行结果:

读测试

使用一个读的控制码,然后在 IRP 的事件中通过控制码区分即可,这里需要注意返回的时候需要设置我们返回给用户层的字节数,不然不一定能接收完整。

用户层调用的时候这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Rtest() {
DWORD dwRetSize = 0;//返回字节数
char *OutBuf = (char *)malloc(0x20);

DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
ReadCode,//控制码 CTL_CODE
NULL,//输入缓冲区指针
0,//输入缓冲区大小
OutBuf,//返回缓冲区
30,//返回缓冲区大小
&dwRetSize,//返回字节数
NULL
);
printf("control code=%x return value=%d\n", WriteCode, dwRetSize);
printf("get message from ring0:%s\n", OutBuf);
}

驱动层随便返回一串字符好了。

1
2
3
4
5
6
7
8
case ReadCode: {
char * buffer = (char *)pirp->AssociatedIrp.SystemBuffer;
char msg[] = "xia0ji233 in ring0";
kprintf(("Line %d:xia0ji233: return Message:%s\n"), __LINE__, msg);
memcpy(buffer, msg, sizeof(msg));
pirp->IoStatus.Information = sizeof(msg);//这里设置给用户层的字节数
break;
}

测试结果:

读写测试

一次的 DeviceIoControl 可以读也可以写,这里我们写一个A+B好了。

三环这里调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void WRtest() {
DWORD dwRetSize = 0;//返回字节数
typedef struct AB{
int a, b;
}AB;
AB InBuf;
int result;
printf("two number>");
scanf("%d%d", &InBuf.a, &InBuf.b);
DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
ReadWriteCode,//控制码 CTL_CODE
&InBuf,//输入缓冲区指针
sizeof(AB),//输入缓冲区大小
&result,//返回缓冲区
4,//返回缓冲区大小
&dwRetSize,//返回字节数
NULL
);
printf("control code=%x return value=%d\n", ReadWriteCode, dwRetSize);
printf("get result from ring0:%d\n", result);
}

驱动这里这么处理:

1
2
3
4
5
6
7
8
9
10
11
12
case ReadWriteCode: {
typedef struct AB {
int a, b;
}AB;
char * buffer = (char *)pirp->AssociatedIrp.SystemBuffer;
AB *s = (AB *)buffer;
kprintf(("Line %d:xia0ji233:get two number %d and %d\n"), __LINE__, s->a, s->b);
int result = s->a + s->b;
memcpy(buffer, &result, sizeof(result));
pirp->IoStatus.Information = sizeof(result);
break;
}

最后来看看结果吧:

三环程序

下面是我总的代码:

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
#include <iostream>
#include <Windows.h>
#define SYMBOL L"\\??\\xia0ji2333"
#define WriteCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ReadCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ReadWriteCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x805,METHOD_BUFFERED, FILE_ANY_ACCESS)

HANDLE DeviceHandle;
void menu() {
printf("------------------------\n");
printf("1.create\n");
printf("2.close\n");
printf("3.wtest\n");
printf("4.rtest\n");
printf("5.Read Write test\n");
printf("6.exit\n");
printf("------------------------\n");
printf("Your choice:");
}
void create() {
DeviceHandle = CreateFile(SYMBOL, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
void close() {
CloseHandle(DeviceHandle);
}
void Wtest() {
DWORD dwRetSize = 0;//返回字节数
char *inBuf = (char *)malloc(0x20);
char *OutBuf = (char *)malloc(0x20);
printf("Your message>");
scanf("%30s", inBuf);

DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
WriteCode,//控制码 CTL_CODE
inBuf,//输入缓冲区指针
strlen(inBuf) + 1,//输入缓冲区大小
OutBuf,//返回缓冲区
20,//返回缓冲区大小
&dwRetSize,//返回字节数
NULL
);
printf("control code=%x\n", WriteCode);
}
void Rtest() {
DWORD dwRetSize = 0;//返回字节数
char *OutBuf = (char *)malloc(0x20);

DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
ReadCode,//控制码 CTL_CODE
NULL,//输入缓冲区指针
0,//输入缓冲区大小
OutBuf,//返回缓冲区
30,//返回缓冲区大小
&dwRetSize,//返回字节数
NULL
);
printf("control code=%x return value=%d\n", WriteCode, dwRetSize);
printf("get message from ring0:%s\n", OutBuf);
}
void WRtest() {
DWORD dwRetSize = 0;//返回字节数
typedef struct AB{
int a, b;
}AB;
AB InBuf;
int result;
printf("two number>");
scanf("%d%d", &InBuf.a, &InBuf.b);
DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
ReadWriteCode,//控制码 CTL_CODE
&InBuf,//输入缓冲区指针
sizeof(AB),//输入缓冲区大小
&result,//返回缓冲区
4,//返回缓冲区大小
&dwRetSize,//返回字节数
NULL
);
printf("control code=%x return value=%d\n", ReadWriteCode, dwRetSize);
printf("get result from ring0:%d\n", result);
}
int main()
{
while (1) {
int ch;
menu();
scanf("%d", &ch);
switch (ch)
{
case 1:
create();
break;
case 2:
close();
break;
case 3:
Wtest();
break;
case 4:
Rtest();
break;
case 5:
WRtest();
break;
default:
exit(0);
break;
}
}
}

驱动总代码

下面是我整个驱动的代码:

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
#include<ntifs.h>
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
#define WriteCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ReadCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ReadWriteCode CTL_CODE (FILE_DEVICE_UNKNOWN,0x805,METHOD_BUFFERED, FILE_ANY_ACCESS)

void DeleteDevice(PDRIVER_OBJECT);

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: {
UINT32 code = irpStackL->Parameters.DeviceIoControl.IoControlCode;
kprintf(("Line %d:xia0ji233: ring3 calls DEVICE CONTROL,control code=%x\n"), __LINE__, code);
switch (code) {
case WriteCode: {
char * buffer = (char *)pirp->AssociatedIrp.SystemBuffer;
kprintf(("Line %d:xia0ji233: Get Message:%s\n"), __LINE__, buffer);
break;
}
case ReadCode: {
char * buffer = (char *)pirp->AssociatedIrp.SystemBuffer;
char msg[] = "xia0ji233 in ring0";
kprintf(("Line %d:xia0ji233: return Message:%s\n"), __LINE__, msg);
memcpy(buffer, msg, sizeof(msg));
pirp->IoStatus.Information = sizeof(msg);
break;
}
case ReadWriteCode: {
typedef struct AB {
int a, b;
}AB;
char * buffer = (char *)pirp->AssociatedIrp.SystemBuffer;
AB *s = (AB *)buffer;
kprintf(("Line %d:xia0ji233:get two number %d and %d\n"), __LINE__, s->a, s->b);
int result = s->a + s->b;
memcpy(buffer, &result, sizeof(result));
pirp->IoStatus.Information = sizeof(result);
break;
}
}

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;
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__);
}