驱动开发初探

0x0 前言

驱动开发的环境配置,以及入门的hello_world
参考链接: https://qwertwwwe.github.io/windows-driver-develop-setup-environment/

0x1 开发及测试环境

开发机系统 : win10, 64位
测试机系统: win7, 32位
开发软件: visual stdio 2015, (vs2017不支持,反正目前官网上是这么说的)

0x2 安装相应的开发软件

官方开发软件下载链接:
https://developer.microsoft.com/zh-cn/windows/hardware/windows-driver-kit
按照官网的教程:

  1. 安装vs2015,打开的时候记得安装Visual C++选项。
  2. 此处可以不选“通用Windows应用开发工具”中的SDK,因为可以从下面的步骤中手动安装。
    1. 安装 Windows SDK, 直接从官网指定的链接下载安装就行;
    2. 安装 Windows WDK, 同样直接从官网指定的链接下载安装;

记得安装的SDK 和 WDK 的版本号必须完全相同,所以我选择SDK和WDK都从官网给的链接上下载安装,避免vs2015中安装的SDK和自己下载的WDK版本不同。

当然WDK和SDK下下来的时候是个执行文件,打开后可以选择直接安装或者近下载,反正都行,我选择先下载下来,后面自己安装,比较这么大软件下一次太久~~

我记得WDK安装的时候会提示什么将无法开发现代应用程序之类的提示,直接接受并继续~~,其实对其他程序开发有什么影响我也不太清楚,反正我这个环境只开发windows驱动程序而已。

0x3 hello-world程序

先用vs2015创建一个新项目

然后在Source Files中新建代码文件 DriverEntry.c,

这里注意一定是.c文件。

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

//DiverUnload是驱动卸载函数,负责清理资源,在卸载驱动的时候调用
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
//指出这个参数并没有使用而不是我们忘记了,防止编译器报错
UNREFERENCED_PARAMETER(pDriverObject);
//表明驱动卸载成功
DbgPrint("Unload Success");
}

//驱动的入口函数相当于三环程序的main
//pDvierObject相当于驱动对象指针,pRegPath相当于注册表路径指针
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
UNREFERENCED_PARAMETER(pRegPath);

//指定驱动的卸载函数
pDriverObject->DriverUnload = DriverUnload;

//表明驱动启动成功
DbgPrint("Hello world");

//ANSI_STRING 1.缓冲区 2.字符串长度 3.最大长度
//UNICODE_STRING 1.缓冲区 2.字符串长度 3.最大长度\x00

//1.字符串常量方式初始化
//1.1 使用WCHAR类型变量进行初始化
UNICODE_STRING usStr1 = { 0 };
WCHAR * szHello = L"Hello WCHAR";
RtlInitUnicodeString(&usStr1, szHello);
KdPrint(("%wS", usStr1.Buffer));
//1.2直接使用字符串初始化
DECLARE_CONST_UNICODE_STRING(usTest, L"Hello Test");
KdPrint(("%wS", usTest.Buffer));

//2.栈空间初始化
//2.1 定义一个字符串结构体
UNICODE_STRING usTest2 = { 0 };
//2.2 在栈上定义一个WCHAR类型的字符串
WCHAR szHello2[512] = L"Hello 512";
//2.3 把WCHAR类型的字符串指向结构体
usTest2.Buffer = szHello2;
//2.4 设置字符串 的实际长度
usTest2.Length = wcslen(L"Hello 512") * sizeof(WCHAR);
//2.5 设置最大长度
usTest2.MaximumLength = sizeof(szHello2);
KdPrint(("%wS", usTest2.Buffer));
//返回成功状态

//3.堆空间初始化
//3.1 定义一个字符串结构题
UNICODE_STRING usTest3 = { 0 };
//3.2 设置字符串长度
ULONG ulLength = ((wcslen(L"Hello 1024"))) * sizeof(WCHAR);
//3.3 在分页内存池里申请一块内存
usTest3.Buffer = ExAllocatePoolWithTag(PagedPool, 256 * sizeof(WCHAR), 'POCU');
//3.4 内存初始化,跟memset一样
RtlZeroMemory(usTest3.Buffer, 256 * sizeof(WCHAR));
//3.5 拷贝字符串、
memcpy(usTest3.Buffer, L"Hello 1024", ulLength);
//3.6 设置字符串长度
usTest3.Length = ulLength;
//3.7 设置字符串最大长度
usTest3.MaximumLength = 256 * sizeof(WCHAR);
//3.8 打印处理,验证一下
KdPrint(("%wS", usTest3.Buffer));
//3.9 释放
ExFreePool(usTest3.Buffer);

//拷贝一个字符串

//1.定义一个目标字符串
UNICODE_STRING dst = { 0 };
//2.定义一个WCHAR类型的变量
WCHAR dst_buf[256];
//3.初始化目标字符串,然后使用RtlInitEmptyUnicodeString而不是RtlInitUnicodeString
RtlInitEmptyUnicodeString(&dst, &dst_buf, 256 * sizeof(WCHAR));
//4.定义源字符串
UNICODE_STRING src = { 0 };
//5.初始化源字符串
RtlInitUnicodeString(&src, L"Hello SRC!");
//6.拷贝
RtlCopyUnicodeString(&dst, &src);
//7.打印,是否成功
KdPrint(("%wS", dst.Buffer));
//返回一个成功的状态

//1. 定义一个字符串
UNICODE_STRING dst2 = { 0 };
//2. 定义一个WCHAR类型的变量,用于预分配
WCHAR dst2_buf[256];
//3. 定义源字符串1
UNICODE_STRING src1 = { 0 };
//4. 定义源字符串2
UNICODE_STRING src2 = { 0 };
//5. 把目的字符串初始化为一个空字符串
RtlInitEmptyUnicodeString(&dst2, &dst2_buf, 256 * sizeof(WCHAR));
//6. 把两个源字符串初始hua
RtlInitUnicodeString(&src1, L"Hello ");
RtlInitUnicodeString(&src2, L"woood");
//7. 把源字符串1拷贝到目标字符串中, 使得目标字符串有值
RtlCopyUnicodeString(&dst2, &src1);
//8. 进行字符串拼接, 把源字符串
RtlAppendUnicodeStringToString(&dst2, &src2);
//9. 显示
KdPrint(("%wS", dst2.Buffer));
return STATUS_SUCCESS;
}

0x4 修改项目属性

  1. 警告等级:

    将警告等级改为3;将警告视为错误改为否;

  2. 修改目标平台属性;
    这个属性决定你生成的程序在什么平台上运行;
    此处我的测试机器是win7 32位。

0x5 在目标机器上运行

  1. 安装必备的软件
    将生成的.sys文件拷贝到目标机器;
    下载一个InstDrv.exe,用来加载驱动程序;
    下载一个Dbgview.exe,用来显示驱动的log;
    两个程序都放在测试的机器里。

  2. 用admin权限打开InstDrv和Dbgview,进行监听。

-------------本文结束感谢您的阅读-------------
+ +