抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

驱动通信

驱动通信

驱动通信

知识点

DRIVER_OBJECT

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
kd> dt _DEVICE_OBJECT
ntdll!_DEVICE_OBJECT
+0x000 Type : Int2B // 设备大小
+0x002 Size : Uint2B
+0x004 ReferenceCount : Int4B
+0x008 DriverObject : Ptr32 _DRIVER_OBJECT
+0x00c NextDevice : Ptr32 _DEVICE_OBJECT
+0x010 AttachedDevice : Ptr32 _DEVICE_OBJECT
+0x014 CurrentIrp : Ptr32 _IRP // 当前请求IRP
+0x018 Timer : Ptr32 _IO_TIMER // 时钟
+0x01c Flags : Uint4B // 以什么方式读写设备
+0x020 Characteristics : Uint4B // 设置属性
+0x024 Vpb : Ptr32 _VPB // 磁盘相关, 暂不涉及
+0x028 DeviceExtension : Ptr32 Void // 扩展
+0x02c DeviceType : Uint4B // 设备类型
+0x030 StackSize : Char // 设备栈的大小
+0x034 Queue : <unnamed-tag> // 队列
+0x05c AlignmentRequirement : Uint4B
+0x060 DeviceQueue : _KDEVICE_QUEUE
+0x074 Dpc : _KDPC
+0x094 ActiveThreadCount : Uint4B
+0x098 SecurityDescriptor : Ptr32 Void
+0x09c DeviceLock : _KEVENT
+0x0ac SectorSize : Uint2B
+0x0ae Spare1 : Uint2B
+0x0b0 DeviceObjectExtension : Ptr32 _DEVOBJ_EXTENSION
+0x0b4 Reserved : Ptr32 Void

IRP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
kd> dt _IRP
ntdll!_IRP
+0x000 Type : Int2B
+0x002 Size : Uint2B
+0x004 MdlAddress : Ptr32 _MDL
+0x008 Flags : Uint4B
+0x00c AssociatedIrp : <unnamed-tag>
+0x010 ThreadListEntry : _LIST_ENTRY
+0x018 IoStatus : _IO_STATUS_BLOCK
+0x020 RequestorMode : Char
+0x021 PendingReturned : UChar
+0x022 StackCount : Char // 总大小(有多少设备)
+0x023 CurrentLocation : Char // 当前设备栈的索引
+0x024 Cancel : UChar
+0x025 CancelIrql : UChar
+0x026 ApcEnvironment : Char
+0x027 AllocationFlags : UChar
+0x028 UserIosb : Ptr32 _IO_STATUS_BLOCK
+0x02c UserEvent : Ptr32 _KEVENT
+0x030 Overlay : <unnamed-tag>
+0x038 CancelRoutine : Ptr32 void
+0x03c UserBuffer : Ptr32 Void
+0x040 Tail : <unnamed-tag>

创建设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NTSTATUS
IoCreateDevice(
_In_ PDRIVER_OBJECT DriverObject, // 要提供的驱动对象
_In_ ULONG DeviceExtensionSize, // 设备扩展, 0代表这个地方没有指向
_In_opt_ PUNICODE_STRING DeviceName, // 设备名称
_In_ DEVICE_TYPE DeviceType, // 设备类型
_In_ ULONG DeviceCharacteristics, // 设备属性
_In_ BOOLEAN Exclusive, // 是否独占
_Outptr_result_nullonfailure_
_At_(*DeviceObject,
__drv_allocatesMem(Mem)
_When_((((_In_function_class_(DRIVER_INITIALIZE))
||(_In_function_class_(DRIVER_DISPATCH)))),
__drv_aliasesMem))
PDEVICE_OBJECT *DeviceObject // 创建成功后返回的驱动对象
);

自定义控制码

1
2
3
4
5
6
7
8
9
10
#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

#define INIT_KEY CTL_CODE(FILE_DEVICE_UNKNOWN, CODE_CTR_INDEX, METHOD_BUFFERED, FILE_ANY_ACCESS)
// 虚拟设备类型 // 索引号 // 通信方式 // 访问权限
#define READ_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN, CODE_CTR_INDEX+1, METHOD_BUFFERED, FILE_ANY_ANY_ACCESS)
#define WRITE_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN, CODE_CTR_INDEX+2, METHOD_BUFFERED, FILE_ANY_ANY_ACCESS)
#define GET_BASE_DLL CTL_CODE(FILE_DEVICE_UNKNOWN, CODE_CTR_INDEX+3, METHOD_BUFFERED, FILE_ANY_ANY_ACCESS)
#define SET_PROTECT_PID CTL_CODE(FILE_DEVICE_UNKNOWN, CODE_CTR_INDEX+4, METHOD_BUFFERED, FILE_ANY_ANY_ACCESS)

创建符号链接

1
2
3
4
5
6
NTKERNELAPI
NTSTATUS
IoCreateSymbolicLink(
_In_ PUNICODE_STRING SymbolicLinkName, // 符号链接名称
_In_ PUNICODE_STRING DeviceName // 设备名称
);

设置驱动派发回调函数

IRP_MJ_CREATEIRP_MJ_CLOSE必须设置

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
// 创建设备开启/关闭回调函数
NTSTATUS MyDriverCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

// 处理 IOCTL 请求
NTSTATUS MyDriverDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// 当前栈
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
// 自定义控制码
ULONG controlCode = stack->Parameters.DeviceIoControl.IoControlCode;

NTSTATUS status = STATUS_SUCCESS;
ULONG_PTR information = 0;

switch (controlCode) {
case IOCTL_MY_CONTROL_CODE: {
// 获取输入输出缓冲区(假设用 METHOD_BUFFERED 方法)
PVOID inputBuffer = Irp->AssociatedIrp.SystemBuffer; // 输入
PVOID outputBuffer = Irp->AssociatedIrp.SystemBuffer; // 输出
ULONG inputBufferLength = stack->Parameters.DeviceIoControl.InputBufferLength;
ULONG outputBufferLength = stack->Parameters.DeviceIoControl.OutputBufferLength;

// 示例:简单地将接收到的输入数据拷贝到输出缓冲区
if (inputBufferLength > 0 && outputBufferLength >= inputBufferLength) {
RtlCopyMemory(outputBuffer, inputBuffer, inputBufferLength);
information = inputBufferLength; // 返回数据的长度
KdPrint(("Received from user: %s\n", (char*)inputBuffer));
}
else {
status = STATUS_BUFFER_TOO_SMALL;
}
break;
}
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}

Irp->IoStatus.Status = status;
Irp->IoStatus.Information = information;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
...
// 设置驱动的卸载例程和设备控制例程
DriverObject->DriverUnload = UnloadDriver;
DriverObject->MajorFunction[IRP_MJ_CREATE] = MyDriverCreate; // 默认派发, 允许打开
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyDriverCreate; // 默认派发, 允许关闭
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyDriverDeviceControl;
}

驱动完整代码

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

// 定义设备名称和符号链接
#define DEVICE_NAME L"\\Device\\MyUniqueDevice"
#define SYM_LINK_NAME L"\\DosDevices\\MyUniqueDevice" // \\??\\ 等价于\\DosDevices\\, \\DosDevices\\兼容性更高

// 定义 IOCTL 控制码
#define IOCTL_MY_CONTROL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

// 创建设备回调函数
NTSTATUS MyDriverCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}


// 驱动卸载函数
void UnloadDriver(PDRIVER_OBJECT DriverObject) {
UNICODE_STRING symLink = RTL_CONSTANT_STRING(SYM_LINK_NAME);
IoDeleteSymbolicLink(&symLink); // 删除符号链接
IoDeleteDevice(DriverObject->DeviceObject); // 删除设备对象
KdPrint(("-----------DriverUnloaded-----------\n"));
}

// 处理 IOCTL 请求
NTSTATUS MyDriverDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// 当前栈
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
// 自定义控制码
ULONG controlCode = stack->Parameters.DeviceIoControl.IoControlCode;

NTSTATUS status = STATUS_SUCCESS;
ULONG_PTR information = 0;

switch (controlCode) {
case IOCTL_MY_CONTROL_CODE: {
// 获取输入输出缓冲区(假设用 METHOD_BUFFERED 方法)
PVOID inputBuffer = Irp->AssociatedIrp.SystemBuffer;
PVOID outputBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG inputBufferLength = stack->Parameters.DeviceIoControl.InputBufferLength;
ULONG outputBufferLength = stack->Parameters.DeviceIoControl.OutputBufferLength;

// 示例:简单地将接收到的输入数据拷贝到输出缓冲区
if (inputBufferLength > 0 && outputBufferLength >= inputBufferLength) {
RtlCopyMemory(outputBuffer, inputBuffer, inputBufferLength);
information = inputBufferLength; // 返回数据的长度
KdPrint(("Received from user: %s\n", (char*)inputBuffer));
}
else {
status = STATUS_BUFFER_TOO_SMALL;
}
break;
}
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}

Irp->IoStatus.Status = status;
Irp->IoStatus.Information = information;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}

// 驱动入口
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
NTSTATUS status;
PDEVICE_OBJECT deviceObject = NULL;
UNICODE_STRING deviceName = RTL_CONSTANT_STRING(DEVICE_NAME);
UNICODE_STRING symLink = RTL_CONSTANT_STRING(SYM_LINK_NAME);

// 创建设备对象
status = IoCreateDevice(DriverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject);
if (!NT_SUCCESS(status)) {
KdPrint(("Failed to create device\n"));
return status;
}

// 创建符号链接
status = IoCreateSymbolicLink(&symLink, &deviceName);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(deviceObject);
KdPrint(("Failed to create symbolic link\n"));
return status;
}

// 设置驱动的卸载例程和设备控制例程
DriverObject->DriverUnload = UnloadDriver;
DriverObject->MajorFunction[IRP_MJ_CREATE] = MyDriverCreate; // 默认派发, 允许打开
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyDriverCreate; // 默认派发, 允许关闭
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyDriverDeviceControl;

KdPrint(("Driver loaded successfully\n"));
return STATUS_SUCCESS;
}

用户态完整代码

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
// 11_01_R3_Communicate(3环通信).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
// 自定义控制码
#define IOCTL_MY_CONTROL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main() {
// 创建设备
HANDLE hDevice = CreateFile(L"\\\\.\\MyUniqueDevice", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("Failed to open device. Error: %d\n", GetLastError());
system("pause");
return 1;
}

char inputBuffer[100] = "Hello, driver!";
char outputBuffer[100] = { 0 };
DWORD bytesReturned;
// 使用DeviceIoControl打开设备并通过自定义控制码发送和接收数据
BOOL success = DeviceIoControl(hDevice,
IOCTL_MY_CONTROL_CODE,
inputBuffer, sizeof(inputBuffer),
outputBuffer, sizeof(outputBuffer),
&bytesReturned, NULL);
if (success) {
printf("Received from driver: %s\n", outputBuffer);
}
else {
printf("DeviceIoControl failed. Error: %d\n", GetLastError());
}

CloseHandle(hDevice);
system("pause");
return 0;
}

使用ReadFile进行通信

驱动代码

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
// 处理读取回调函数
NTSTATUS MyDriverDeviceReadControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG bufferLength = stack->Parameters.Read.Length;
NTSTATUS status = STATUS_SUCCESS;

// 准备要发送到用户态的数据
const char* message = "Hello From Kernel!";
ULONG messageLength = (ULONG)strlen(message) + 1;

// 检查缓冲区大小
if (bufferLength < messageLength) {
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
}
else {
// 将数据复制到用户态缓冲区
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, message, messageLength);
Irp->IoStatus.Information = messageLength; // 返回数据长度
}

Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
// 创建设备
...
deviceObject->Flags |= DO_BUFFERED_IO;
// 创建符号链接
...
// 设置回调函数
DriverObject->DriverUnload = UnloadDriver;
DriverObject->MajorFunction[IRP_MJ_CREATE] = MyDriverCreate; // 默认派发, 允许打开
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyDriverCreate; // 默认派发, 允许关闭
DriverObject->MajorFunction[IRP_MJ_READ] = MyDriverDeviceReadControl;
}

用户态代码

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
// 11_01_R3_Communicate(3环通信).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <windows.h>
#include <winioctl.h>
#include <stdio.h>

#define IOCTL_MY_CONTROL_CODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main() {
// 创建设备
HANDLE hDevice = CreateFile(TEXT("\\\\.\\MyUniqueDevice"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("Failed to open device. Error: %d\n", GetLastError());
system("pause");
return 1;
}

char buffer[100] = { 0 };
DWORD bytesRead;

// 使用 ReadFile 从驱动读取数据
BOOL success = ReadFile(hDevice, buffer, sizeof(buffer), &bytesRead, NULL);
if (success) {
printf("Received from driver: %s\n", buffer);
}
else {
printf("ReadFile failed. Error: %d\n", GetLastError());
}

CloseHandle(hDevice);
system("pause");
return 0;
}

通信方式

1
2
3
4
#define METHOD_BUFFERED                 0       // 缓冲模式, 复制一份数据
#define METHOD_IN_DIRECT 1 // 映射同一个物理地址, 共享物理地址
#define METHOD_OUT_DIRECT 2 //
#define METHOD_NEITHER 3 // 直写

驱动通信封装

步骤

  1. 注册通信方法
  2. 销毁的方法
  3. 发送通知

注意

在使用WriteFile时第四个参数不能使用LPDWORD指针类型直接传参, 会导致程序奔溃, 需要使用DWORD类型然后传递指针;

评论