前言

请先看前一篇博客,不然可能不理解这里面的部分内容

目标

由于我们只用写一个驱动程序,且只有一个设备,所以devnode只有一个节点,因为没有下层总线驱动,所以直接由它实现IoComplite即可。

说到R0和R3通信,实际就是R3如何控制R0驱动的行为,为上层应用实现内核级别的操作。所以要实现数据交换。目前学到的通信均为IRP实现的通信(后面还有快速IO),而处理IRP的驱动(目前)只有两种交换数据的方式:

  • 缓冲IO
  • 直接IO

如果不使用默认的操作码,还可以用IRP_MJ_DEVICE_CONTROL来实现自定义操作码。所以这次使用以上三种方法来实现R0到R3的通信。

那么具体来说:

  • 创建设备对象后设置DO_BUFFER_IO或DO_DIRECT_IO
  • 在对应的IRP回调中在AssociatedIrp.SystemBuffer/MmGetSystemAddressForMdlSafe中获取指针来读取/写入内容
  • 进行一个自定义操作,使用IRP_MJ_DEVICE_CONTROL作为主码

具体实现

DO_BUFFER_IO的实现

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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <wdm.h>
//#include <ntddk.h>

#define DEVICENAME L"\\DEVICE\\DeviceTest"
#define SYMNAME L"\\??\\SymboilcLinkTest"


void DrvUnload(PDRIVER_OBJECT pdriver) {

if (pdriver->DeviceObject)
{
IoDeleteDevice(pdriver->DeviceObject);
UNICODE_STRING symname = {};
RtlInitUnicodeString(&symname, SYMNAME);
IoDeleteSymbolicLink(&symname);
}


DbgPrint("Driver Unloaded\n");
}
NTSTATUS myCreate(PDEVICE_OBJECT pdevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;

DbgPrint("my divice has be opened\n");

pirp->IoStatus.Status = status;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);

return status;
}
NTSTATUS myClose(PDEVICE_OBJECT pdevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;

DbgPrint("my divice has be closed\n");

pirp->IoStatus.Status = status;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);

return status;
}
NTSTATUS myCleanup(PDEVICE_OBJECT pdevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;

DbgPrint("my divice has be cleaned\n");

pirp->IoStatus.Status = status;
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT);

return status;
}

// 实现请求
NTSTATUS myRead(PDEVICE_OBJECT pdevice, PIRP pirp)
{
DbgPrint("start reading\n");

// 获取当前IO栈位置
PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);

// 从参数域获得相关数据
DWORD32 askdDataLen = pstack->Parameters.Read.Length;
PCHAR pR0buffer = pirp->AssociatedIrp.SystemBuffer;

// 发送的数据
char data[] = "This is a data from kernel";

if (askdDataLen >= sizeof(data))
{
RtlCopyMemory(pR0buffer, data, sizeof(data));
// info表明实际返回大小
pirp->IoStatus.Information = sizeof(data);
}
else
{
RtlCopyMemory(pR0buffer, data, askdDataLen);
pirp->IoStatus.Information = askdDataLen;

}

pirp->IoStatus.Status = STATUS_SUCCESS;

// 不提升等待这个irp的其它线程的优先级,并完成
IoCompleteRequest(pirp, IO_NO_INCREMENT);

}

NTSTATUS myWrite(PDEVICE_OBJECT pdevice, PIRP pirp)
{
DbgPrint("start writing\n");

// 获取当前IO栈位置
PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);

// 从参数域获得相关数据
DWORD32 askdDataLen = pstack->Parameters.Write.Length;
PCHAR pR0buffer = pirp->AssociatedIrp.SystemBuffer;
PCHAR deviceBuffer = pdevice->DeviceExtension;
size_t maxSize = 0x100;
//先清空数据
RtlZeroMemory(deviceBuffer, maxSize);
// 读取的数据

if (askdDataLen <= maxSize)
{
RtlCopyMemory(deviceBuffer, pR0buffer, askdDataLen);
// info表明实际返回大小
pirp->IoStatus.Information = askdDataLen;
DbgPrint("%p,%s,%d", deviceBuffer, deviceBuffer, askdDataLen);

}
else
{
RtlCopyMemory(deviceBuffer, pR0buffer, maxSize);
pirp->IoStatus.Information = maxSize;
DbgPrint("%p,%s,%d", deviceBuffer, deviceBuffer, maxSize);

}


pirp->IoStatus.Status = STATUS_SUCCESS;

// 不提升等待这个irp的其它线程的优先级,并完成
IoCompleteRequest(pirp, IO_NO_INCREMENT);

}

// 定义操作码
#define IOCTL_MYFUNC1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x901,METHOD_BUFFERED,FILE_ANY_ACCESS)

// 实现对数据的异或
NTSTATUS processMyFunc1(PDEVICE_OBJECT pdevice, PIRP pirp)
{
PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);
DWORD32 inlen = pstack->Parameters.DeviceIoControl.InputBufferLength;
DWORD32 outlen = pstack->Parameters.DeviceIoControl.OutputBufferLength;
PCHAR pData = pirp->AssociatedIrp.SystemBuffer;
for (int i = 0; i < inlen; ++i)
{
pData[i] ^= 0xaa;
}
pirp->IoStatus.Information = inlen;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

NTSTATUS myControl(PDEVICE_OBJECT pdevice, PIRP pirp)
{
PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);
DWORD32 code = pstack->Parameters.DeviceIoControl.IoControlCode;
NTSTATUS status = STATUS_SUCCESS;
switch (code)
{
case IOCTL_MYFUNC1:
status = processMyFunc1(pdevice, pirp);
break;
default:
break;
}
return status;
}

NTSTATUS DriverEntry(
PDRIVER_OBJECT driver,
PUNICODE_STRING reg_path
)
{
driver->DriverUnload = DrvUnload;


UNICODE_STRING deviceName = { 0 };
RtlInitUnicodeString(&deviceName, DEVICENAME);
PDEVICE_OBJECT pdevice = NULL;
// 为设备准备0x100字节的空间放数据
NTSTATUS status = IoCreateDevice(driver, 0x100, &deviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pdevice);

if (!NT_SUCCESS(status))
{
DbgPrint("Create Device fail:%x\n", status);
return status;
}

UNICODE_STRING symname = { 0 };

RtlInitUnicodeString(&symname, SYMNAME);
status = IoCreateSymbolicLink(&symname, &deviceName);

if (!NT_SUCCESS(status))
{
DbgPrint("Create symbolicLink fail:%x\n", status);
IoDeleteDevice(pdevice);
return status;
}
DbgPrint("In DriverEntry!\n");

// 设置缓冲IO
pdevice->Flags |= DO_BUFFERED_IO;

driver->MajorFunction[IRP_MJ_CREATE] = myCreate;
driver->MajorFunction[IRP_MJ_CLOSE] = myClose;
driver->MajorFunction[IRP_MJ_CLEANUP] = myCleanup;
driver->MajorFunction[IRP_MJ_READ] = myRead;
driver->MajorFunction[IRP_MJ_WRITE] = myWrite;

// 自定义IRP
driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = myControl;
return 0;
}

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
//R3
#include <Windows.h>
#include <iostream>

#define SYMNAME L"\\\\.\\SymboilcLinkTest"
#define IOCTL_MYFUNC1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x901,METHOD_BUFFERED,FILE_ANY_ACCESS)

int main() {
HANDLE hDevice = CreateFile(SYMNAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (hDevice == INVALID_HANDLE_VALUE) {
std::cout << "Failed to open device: " << GetLastError() << std::endl;
return 1;
}

std::cout << "Device opened successfully!" << std::endl;
system("pause");
BYTE readBuffer[50] = {};
DWORD dataLen = 0;



// 从对应句柄中读取,可以通过在driver中修改偏移来实现读取不同的内容
ReadFile(hDevice, readBuffer, 50, &dataLen, NULL);

printf("%p,%s,%d\n", readBuffer, readBuffer, dataLen);


system("pause");


BYTE dataWattingForWrite[] = "data from application";
WriteFile(hDevice, dataWattingForWrite, sizeof(dataWattingForWrite), &dataLen, NULL);


// 实现自定义函数

DWORD32 x[] = { 0,1,2,3 };
DWORD32 y[4] = {};
DeviceIoControl(hDevice, IOCTL_MYFUNC1, x, sizeof(x), &y, 4, &dataLen, NULL);

printf("%x %x %x %x", y[0], y[1], y[2], y[3]);

CloseHandle(hDevice);
return 0;

}