Windows驱动开发 用户层与内核层通信

内核层

用户层与内核层通信可以使用IoCreateDeviceSecure函数创建的设备(Device)作为中间媒介IoCreateDeviceSecure在成功情况下会通过参数返回一个DeviceObject,此时的设备还不能直接被用户层程序使用,需要为其创建一个符号链接(Symbolic Link).

创建好符号链接后可以被用户层程序使用.设备本身有自己的名字,比如\\Device\\mydevice_1tyuf2uhiu,符号链接可以理解为是供用户层使用的别名,比如\\??\\mydevice_sym_1tyuf2uhiu.

另外,内核层的符号链接和用户层的符号链接也不太一样,比如对于\\??\\mydevice_sym_1tyuf2uhiu这个内核层的符号链接,在用户层访问需要改成\\\\.\\mydevice_sym_1tyuf2uhiu才能正确访问设备.

根据MSDN的说法,通过IO请求传输数据给驱动需要使用IRP作为信息的载体,为驱动(Driver)设置Major Function的Dispatcher是因为IO请求包括许多类操作,包括从设备读取数据、向设备写入数据、开启/关闭设备等,这样就可以编写不同的Dispatcher函数来处理不同的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
#include <ntifs.h>
#include <wdmsec.h>

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
VOID DriverUnload(PDRIVER_OBJECT DriverObject);
NTSTATUS MyDispatcher(IN PDEVICE_OBJECT Device, IN PIRP Irp);

static const GUID DeviceClassGuid =
{ 0xe8ac357a, 0x4a7f, 0x46ce, { 0xa1, 0x5e, 0x9d, 0x4c, 0x8a, 0x94, 0xb9, 0xd4 } };
PDEVICE_OBJECT DeviceObject;
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\mydevice_1tyuf2uhiu");
UNICODE_STRING DeviceSymName = RTL_CONSTANT_STRING(L"\\??\\mydevice_sym_1tyuf2uhiu");
UNICODE_STRING SDDLString = RTL_CONSTANT_STRING(L"D:P(A;;GA;;;WD)");
#define CTL_CODE_SEND_PTR \
(ULONG) CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x900, \
METHOD_BUFFERED, \
FILE_WRITE_DATA \
)
#define CTL_CODE_RECV_PTR \
(ULONG) CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x901, \
METHOD_BUFFERED, \
FILE_READ_DATA \
)

NTSTATUS DriverEntry(PDRIVER_OBJECT _DriverObject, PUNICODE_STRING _RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
_DriverObject->DriverUnload = DriverUnload;
DbgPrint("[TEST] Hello World\r\n");
status = IoCreateDeviceSecure(
_DriverObject,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&SDDLString,
&DeviceClassGuid,
&DeviceObject
);
if (!NT_SUCCESS(status))
{
return status;
}
IoDeleteSymbolicLink(&DeviceSymName);
status = IoCreateSymbolicLink(&DeviceSymName, &DeviceName);
if (!NT_SUCCESS(status))
{
return status;
}
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
_DriverObject->MajorFunction[i] = MyDispatcher;
}
return status;
}

VOID DriverUnload(PDRIVER_OBJECT _DriverObject)
{
ASSERT(DeviceObject != NULL);
IoDeleteSymbolicLink(&DeviceSymName);
IoDeleteDevice(DeviceObject);
}

NTSTATUS MyDispatcher(IN PDEVICE_OBJECT _Device, IN PIRP _Irp)
{
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(_Irp);
NTSTATUS status = STATUS_SUCCESS;
ULONG ret_len = 0;
while (_Device == DeviceObject)
{
if (irpsp->MajorFunction == IRP_MJ_CREATE || irpsp->MajorFunction == IRP_MJ_CLOSE)
{
break;
}
if (irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
PVOID buffer = _Irp->AssociatedIrp.SystemBuffer;
ULONG inlen = irpsp->Parameters.DeviceIoControl.InputBufferLength;
ULONG outlen = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
{
case CTL_CODE_SEND_PTR:
ASSERT(buffer != NULL);
ASSERT(inlen > 0);
ASSERT(outlen == 0);
DbgPrint("[TEST] get buffer: %s\r\n", (char*)buffer);
break;
case CTL_CODE_RECV_PTR:
default:
status = STATUS_INVALID_PARAMETER;
break;
}
}
break;
}
_Irp->IoStatus.Information = ret_len;
_Irp->IoStatus.Status = status;
IoCompleteRequest(_Irp, IO_NO_INCREMENT);
return status;
}

用户层

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
#include <cstdio>
#include <Windows.h>

#define CTL_CODE_SEND_PTR \
(ULONG) CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x900, \
METHOD_BUFFERED, \
FILE_WRITE_DATA \
)
#define CTL_CODE_RECV_PTR \
(ULONG) CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x901, \
METHOD_BUFFERED, \
FILE_READ_DATA \
)

LPCWSTR DeviceSymName = L"\\\\.\\mydevice_sym_1tyuf2uhiu";

int main()
{
LPCSTR message = "HELLO DEVICE.\r\n";
HANDLE hDevice = CreateFile(
DeviceSymName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM,
NULL
);
DWORD ret_len = 0;
BOOL result = FALSE;
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("[-]Cannot create file handle. Error Code: %d\n", GetLastError());
return 0;
}
printf("[+] Openning device successfully\n");
result = DeviceIoControl(hDevice, CTL_CODE_SEND_PTR, (LPVOID)message, strlen(message) + 1, NULL, 0, &ret_len, NULL);
if (!result)
{
printf("[-]Cannot send message. Error Code: %d\n", GetLastError());
return 0;
}
printf("[+] Sending message successfully\n");
CloseHandle(hDevice);
hDevice = NULL;
return 0;
}