首页
社区
课程
招聘
[分享]这段时间学习驱动开发的相关的一些笔记
2021-2-15 20:28 20754

[分享]这段时间学习驱动开发的相关的一些笔记

2021-2-15 20:28
20754

这段时间学习了一下驱动开发,当然只是一点点皮毛,主要是记录一下,怕后面又搞忘了。

目录

驱动学习1--环境搭建

驱动学习2--第一个驱动HelloDriver

驱动学习2--为驱动创建设备对象

驱动学习3--为驱动绑定符号链接

驱动学习4--处理驱动的IRP 事件

驱动学习5--用户层调用驱动实现相互通信

驱动学习6--驱动的加载执行和停止卸载

驱动学习7--SSDT HOOK(x86 架构下)


驱动学习1--环境搭建

  1. WinDbg 双机调试环境:https://www.bbsmax.com/A/gGdXgRk754/
  2. WDK 驱动开发环境:
    下载WDK 安装环境
    链接:https://pan.baidu.com/s/18nG2bKGI1C1HhwqLiEMPDw
    提取码:0o0w
  3. 驱动加载工具和调试信息工具
    IstDrv.exe 驱动加载
    DbgView 调试信息查看

驱动学习2--第一个驱动HelloDriver

代码编写前的一些配置

1
2
3
4
5
6
7
编写驱动前环境设置(仅为不使用框架时使用)
1. 属性 -> C/C++ -> 警告等级 : 等级3 / W3
2. 属性 -> C/C++ -> 将警告视为错误 : 否
3. 属性 -> Inf2Cat -> Run Inf2Cat : 否
4. 属性 -> Driver Settings -> Target Os Version : 设置对应的系统版本
5. 属性 -> Driver Settings -> Target PlaForm : Desktop
6. 属性 -> StampInf -> Enable ArchiteCture : 否

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 驱动头文件
#include <ntddk.h>
 
void DriverUnload(PDRIVER_OBJECT obj)
{
    KdPrint(("JJR:驱动卸载函数启动"));
}
 
// 驱动入口点
NTSTATUS DriverEntry(/*驱动对象*/ PDRIVER_OBJECT obj, /*驱动注册路径*/PUNICODE_STRING registePath)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("JJR:驱动安装函数启动"));
    // 指定卸载函数
    obj->DriverUnload = DriverUnload;
    return status;
}

驱动的入口点函数为DriverEntry() 函数,函数在调用时会默认传入两个参数,分别是驱动对象指针(PDRIVER_OBJECT)和驱动注册路径(PUNICODE_STRING),驱动对象指针顾名思义是指代指向驱动对象的指针对象,而驱动注册路径是指驱动在注册表中注册的具体路径。
图片描述
驱动对象成员DriverUnload 指向驱动卸载回调函数,当驱动停止并卸载时该函数会启动。

驱动学习2--为驱动创建设备对象

为驱动创建设备使用到的函数未IoCreateDevice(), 函数定义如下:

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
NTSTATUS IoCreateDevice
(
IN PDRIVER_OBJECT DriverObject,//驱动对象
IN ULONG DeviceExtensionSize,//指定驱动程序为设备扩展对象而
//定义的结构体的大小.
IN PUNICODE_STRING DeviceName OPTIONAL,//设备名称,只能在内
//核层使用
IN DEVICE_TYPE DeviceType,// 设备类型
IN ULONG DeviceCharacteristics,//大多数驱动程序为此参数指定
//FILE_DEVICE_SECURE_OPEN。,指定一个或多个系统定义的常量,连
//接在一起,提供有关驱动程序的设备其他信息.对于可能的设备特征信
//
IN BOOLEAN Exclusive,//如果指定设备是独占的,大部分驱动程序设
//置这个值为FALSE,如果是独占的话设置为TRUE,非独占设置为FALSE.
OUT PDEVICE_OBJECT *DeviceObject//一个指向DEVICE_OBJECT结构
//体指针的指针,这是一个指针的指针,指向的指针用来接收
//DEVICE_OBJECT结构体的指针,返回创建的设备对象,在卸载驱动的时
//候,需要对这个设备对象进行删除:IoDeleteDevice()
);
 
 
独占就是在用户层(R3)使用CreateFile 获取驱动句柄只能进行
一次,再次获取需要对之前的句柄进行释放。而非独占可以多次获取
该驱动的句柄
 
其中,设备驱动类型可以取如下的值:
#define FILE_DEVICE_8042_PORT           0x00000027
#define FILE_DEVICE_ACPI                0x00000032
#define FILE_DEVICE_BATTERY             0x00000029
#define FILE_DEVICE_BEEP                0x00000001
#define FILE_DEVICE_BUS_EXTENDER        0x0000002a
#define FILE_DEVICE_CD_ROM              0x00000002
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
#define FILE_DEVICE_CHANGER             0x00000030
#define FILE_DEVICE_CONTROLLER          0x00000004
#define FILE_DEVICE_DATALINK            0x00000005
#define FILE_DEVICE_DFS                 0x00000006
#define FILE_DEVICE_DFS_FILE_SYSTEM     0x00000035
#define FILE_DEVICE_DFS_VOLUME          0x00000036
#define FILE_DEVICE_DISK                0x00000007
#define FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
#define FILE_DEVICE_DVD                 0x00000033
#define FILE_DEVICE_FILE_SYSTEM         0x00000009
#define FILE_DEVICE_FIPS                0x0000003a
#define FILE_DEVICE_FULLSCREEN_VIDEO    0x00000034
#define FILE_DEVICE_INPORT_PORT         0x0000000a
#define FILE_DEVICE_KEYBOARD            0x0000000b
#define FILE_DEVICE_KS                  0x0000002f
#define FILE_DEVICE_KSEC                0x00000039
#define FILE_DEVICE_MAILSLOT            0x0000000c
#define FILE_DEVICE_MASS_STORAGE        0x0000002d
#define FILE_DEVICE_MIDI_IN             0x0000000d
#define FILE_DEVICE_MIDI_OUT            0x0000000e
#define FILE_DEVICE_MODEM               0x0000002b
#define FILE_DEVICE_MOUSE               0x0000000f
#define FILE_DEVICE_MULTI_UNC_PROVIDER  0x00000010
#define FILE_DEVICE_NAMED_PIPE          0x00000011
#define FILE_DEVICE_NETWORK             0x00000012
#define FILE_DEVICE_NETWORK_BROWSER     0x00000013
#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
#define FILE_DEVICE_NETWORK_REDIRECTOR  0x00000028
#define FILE_DEVICE_NULL                0x00000015
#define FILE_DEVICE_PARALLEL_PORT       0x00000016
#define FILE_DEVICE_PHYSICAL_NETCARD    0x00000017
#define FILE_DEVICE_PRINTER             0x00000018
#define FILE_DEVICE_SCANNER             0x00000019
#define FILE_DEVICE_SCREEN              0x0000001c
#define FILE_DEVICE_SERENUM             0x00000037
#define FILE_DEVICE_SERIAL_MOUSE_PORT   0x0000001a
#define FILE_DEVICE_SERIAL_PORT         0x0000001b
#define FILE_DEVICE_SMARTCARD           0x00000031
#define FILE_DEVICE_SMB                 0x0000002e
#define FILE_DEVICE_SOUND               0x0000001d
#define FILE_DEVICE_STREAMS             0x0000001e
#define FILE_DEVICE_TAPE                0x0000001f
#define FILE_DEVICE_TAPE_FILE_SYSTEM    0x00000020
#define FILE_DEVICE_TERMSRV             0x00000038
#define FILE_DEVICE_TRANSPORT           0x00000021
#define FILE_DEVICE_UNKNOWN             0x00000022
#define FILE_DEVICE_VDM                 0x0000002c
#define FILE_DEVICE_VIDEO               0x00000023
#define FILE_DEVICE_VIRTUAL_DISK        0x00000024
#define FILE_DEVICE_WAVE_IN             0x00000025
#define FILE_DEVICE_WAVE_OUT            0x00000026

创建驱动设备对象源码:

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
// 驱动头文件
#include <ntddk.h>
 
// 驱动名称格式\\DEVICE\\YOUR_DEVICE_NAME
#define DEVICE_NAME L"\\DEVICE\\MyDevice"
 
void DriverUnload(PDRIVER_OBJECT obj)
{
    // 删除驱动设备
    // 这里驱动对象所包含的设备对象与我们创建的设备对象是同一个对象
    IoDeleteDevice(obj->DeviceObject);
    KdPrint(("JJR:驱动卸载函数启动"));
}
 
// 为驱动创建设备对象
NTSTATUS createDevice(PDRIVER_OBJECT obj)
{
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    NTSTATUS status = STATUS_SUCCESS;
    // 初始化驱动设备名称
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 驱动对象
    DEVICE_OBJECT deviceObj;
    status = IoCreateDevice(
        obj,
        0x4,
        &deviceName,
        FILE_DEVICE_UNKNOWN,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &deviceObj
    );
    return status;
}
 
// 驱动入口点
NTSTATUS DriverEntry(/*驱动对象*/ PDRIVER_OBJECT obj, /*驱动注册路径*/PUNICODE_STRING registePath)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("JJR:驱动安装函数启动"));
    // 指定卸载函数
    obj->DriverUnload = DriverUnload;
 
    if (createDevice(obj) == STATUS_SUCCESS)
    {
        KdPrint(("JJR:驱动设备创建成功"));
    }
    return status;
}

驱动设备对象创建使用IoCreateDevice 函数,创建好的驱动设备对象可以由驱动对象指针指出,指出的该对象与函数创建时返回的对象为同一个对象。IoCreateDevice 函数返回为STATUS_SUCCESS 是表示创建驱动设备对象成功。驱动设备对象名称格式为"\DEVICE\YOUR_DEVICE_NAME",其中,DEVICE 可小写。驱动在卸载的时候需要调用IoDeleteDevice 函数删除驱动设备对象。驱动设备对象是供内核层(R0)调用时使用的,在用户层(R3)调用驱动使用的是驱动符号链接。

驱动学习3--为驱动绑定符号链接

驱动设备对象无法在用户层得到调用,要实现在用户层实现对驱动的控制,需要为驱动绑定符号链接。通过使用IoCreateSysbolicLink 函数为驱动绑定符号链接。函数原型如下:

1
2
3
4
NTSTATUS IoCreateSymbolicLink(
  PUNICODE_STRING SymbolicLinkName,// 符号链接名称,unicode 字符串
  PUNICODE_STRING DeviceName// 设备名称
);

通常在调用IoCreateDevice 创建设备对象的时候回传入设备名称,这个设备名称只能在内核层使用,只能被内核层的函数识别。如果IoCreateDevice 中没有指定设备名称,那么I/O管理器会自动分配一个数字作为设备的名称。例如"\Device\00000001"。
如果想要在用户层的应用程序中访问(比如调用CreateFile 函数打开),就需要创建符号链接,相当于为设备对象创建一个别名,供应用程序访问。应用层是无法直接通过设备名字来打开对象的,必须建立一个暴露给应用程序的符号链接。
比如:C盘的符号链接名称是"C:",对应的设备名称是"\Device\HarddiskVolume1"。
驱动创建符号链接代码:

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
// 驱动头文件
#include <ntddk.h>
 
// 驱动名称格式\\DEVICE\\YOUR_DEVICE_NAME
#define DEVICE_NAME L"\\device\\MyDevice"
// 驱动链接名称,格式为\\??\\YOUR_SYMBOLLINK_NAME
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
 
void DriverUnload(PDRIVER_OBJECT obj)
{
    // 删除符号链接
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    IoDeleteSymbolicLink(&SymbolLinkName);
    // 删除驱动设备
    // 这里驱动对象所包含的设备对象与我们创建的设备对象是同一个对象
    IoDeleteDevice(obj->DeviceObject);
    KdPrint(("JJR:驱动卸载函数启动"));
}
 
// 为驱动创建设备对象
NTSTATUS createDevice(PDRIVER_OBJECT obj)
{
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    NTSTATUS status = STATUS_SUCCESS;
    // 初始化驱动设备名称
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 驱动对象
    DEVICE_OBJECT deviceObj;
    status = IoCreateDevice(
        obj,
        0x4,
        &deviceName,
        FILE_DEVICE_UNKNOWN,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &deviceObj
    );
    return status;
}
 
// 为驱动绑定符号链接
NTSTATUS createSymbolLink()
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    // 驱动设备名称
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    status = IoCreateSymbolicLink(&SymbolLinkName, &deviceName);
    return status;
 
}
 
// 驱动入口点
NTSTATUS DriverEntry(/*驱动对象*/ PDRIVER_OBJECT obj, /*驱动注册路径*/PUNICODE_STRING registePath)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("JJR:驱动安装函数启动"));
    // 指定卸载函数
    obj->DriverUnload = DriverUnload;
 
    if (createDevice(obj) == STATUS_SUCCESS)
    {
        KdPrint(("JJR:驱动设备创建成功"));
        if (createSymbolLink() == STATUS_SUCCESS)
        {
            KdPrint(("JJR:驱动符号链接创建成功"));
        }
    }
    return status;
}

驱动学习4--处理驱动的IRP 事件

在用户层对驱动符号链接进行操作时,会产生相应的IRP 事件,在驱动内对IRP 进行操作,实现用户层对驱动的操作。
实现对IRP 事件的处理需要使用到派遣函数:

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
NTSTATUS DriverIRPCtl(PDEVICE_OBJECT obj, PIRP pIrp)
{
    PIO_STACK_LOCATION pIoStackLocation = NULL;
        KdPrint(("进入派遣函数"));
        // 获取用户层调用时产生的具体的IRP 事件   
        pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
     // 判断不同的IRP 事件
        switch (pIoStackLocation->MajorFunction)
        {
        case IRP_MJ_CREATE: // 用户层开启了驱动
        {
            KdPrint(("用户层调用了CreateFile()"));
        }; break;
        case IRP_MJ_CLOSE: // 用户层关闭了驱动
        {
            KdPrint(("用户层调用了CloseHandle()"));
        }
        default:
            break;
    }
    pIrp->IoStatus.Status = STATUS_SUCCESS;
    pIrp->IoStatus.Information = 4;// 返回给DeviceIoControl 中的倒数第二个参数lpBytesReturned
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    KdPrint(("退出派遣函数"));
    return STATUS_SUCCESS;
}

在驱动内对特定的事件绑定派遣回调函数:

1
2
3
4
obj->MajorFunction[IRP_MJ_CREATE] = DriverIRPCtl; // 指定驱动打开的派遣函数
obj->MajorFunction[IRP_MJ_CLOSE] = DriverIRPCtl; // 指定驱动关闭的派遣函数
// 派遣函数可以为多个,也可以指定应该。不同的是当指定应该函数时,需要
// 对传入的IRP 事件进行判断

具体实现代码:

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 <ntddk.h>
 
// 驱动名称格式\\DEVICE\\YOUR_DEVICE_NAME
#define DEVICE_NAME L"\\device\\MyDevice"
// 驱动链接名称,格式为\\??\\YOUR_SYMBOLLINK_NAME
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
 
// 驱动派遣回调函数
NTSTATUS DriverIRPCtrl(PDEVICE_OBJECT obj, PIRP pIrp)
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 当前IO 栈,用于存放用户层调用时产生的IRP 事件
    PIO_STACK_LOCATION pIoStackLocation = NULL;
    // 获取用户层调用时产生的IRP 函数
    pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
    // 判断IRP 事件类型
    switch (pIoStackLocation->MajorFunction)
    {
        case IRP_MJ_CREATE:
        {
            // 用户层使用CreateFile 调用驱动
            KdPrint(("JJR:用户层调用CreateFile 开启对驱动的调用"));
        }; break;
        case IRP_MJ_CLOSE:
        {
            // 用户层使用CloseHandle 结束驱动调用
            KdPrint(("JJR:用户层调用CLoseHandle 结束对驱动的调用"));
        }; break;
        default:
            break;
    }
 
    return status;
}
 
 
void DriverUnload(PDRIVER_OBJECT obj)
{
    // 删除符号链接
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    IoDeleteSymbolicLink(&SymbolLinkName);
    // 删除驱动设备
    // 这里驱动对象所包含的设备对象与我们创建的设备对象是同一个对象
    IoDeleteDevice(obj->DeviceObject);
    KdPrint(("JJR:驱动卸载函数启动"));
}
 
// 为驱动创建设备对象
NTSTATUS createDevice(PDRIVER_OBJECT obj)
{
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    NTSTATUS status = STATUS_SUCCESS;
    // 初始化驱动设备名称
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 驱动对象
    DEVICE_OBJECT deviceObj;
    status = IoCreateDevice(
        obj,
        0x4,
        &deviceName,
        FILE_DEVICE_UNKNOWN,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &deviceObj
    );
    return status;
}
 
// 为驱动绑定符号链接
NTSTATUS createSymbolLink()
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    // 驱动设备名称
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    status = IoCreateSymbolicLink(&SymbolLinkName, &deviceName);
    return status;
 
}
 
// 驱动入口点
NTSTATUS DriverEntry(/*驱动对象*/ PDRIVER_OBJECT obj, /*驱动注册路径*/PUNICODE_STRING registePath)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("JJR:驱动安装函数启动"));
    // 指定卸载函数
    obj->DriverUnload = DriverUnload;
    // 为IRP 事件指定派遣函数,指定的派遣函数可以为不同的事件不同的函数
    // 当用户层调用CreateFile 函数时产生的IRP 事件
    obj->MajorFunction[IRP_MJ_CREATE] = DriverIRPCtrl;
    // 当用户层调用CloseHandle 函数时产生的IRP 事件
    obj->MajorFunction[IRP_MJ_CLOSE] = DriverIRPCtrl;
 
    if (createDevice(obj) == STATUS_SUCCESS)
    {
        KdPrint(("JJR:驱动设备创建成功"));
        if (createSymbolLink() == STATUS_SUCCESS)
        {
            KdPrint(("JJR:驱动符号链接创建成功"));
        }
    }
    return status;
}

在代码中,派遣函数定义了一个,并且在派遣函数内部通过IoGetCurrentIrpStackLocation 函数获取了具体的IRP 事件进行不同的执行。在驱动入口函数内,使用:

1
obj->MajorFunction[IRP_TYPE] = FUNC;

指定了对应事件[IRP_TYPE] 所需要执行的派遣函数FUNC。派遣函数不唯一,不同的IRP 事件也可以指向不同的IRP 函数。

驱动学习5--用户层调用驱动实现相互通信

上面说到了驱动层处理用户层调用时产生的IRP 事件的方式--派遣函数。在用户层通过对之前为驱动绑定的符号链接进行操作实现对驱动的操作。所使用到的函数为CreateFile():

1
2
3
4
5
6
7
8
9
10
HANDLE CreateFile(
  LPCTSTR lpFileName,          // 文件名称,这里指符号链接名称
  DWORD dwDesiredAccess,       // 读取权限
  DWORD dwShareMode,           // 共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                               // 安全属性
  DWORD dwCreationDisposition,  // 创建方式
  DWORD dwFlagsAndAttributes,  // 文件属性
  HANDLE hTemplateFile         // 复制文件所使用的句柄
);

使用CreateFile 函数对驱动设备打开并执行后续操作。使用CloseHandle 函数关闭对驱动的使用:

1
2
3
BOOL CloseHandle(
  HANDLE hObject   // 对象句柄
);

具体代码:
// 驱动层代码即上一次编写的代码
// 用户层代码

1
2
3
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
// 驱动对象句柄
HANDLE hDriver = (HANDLE)0xFFFFFFFF;
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
// 开始驱动调用
void CR3AppForMyDriverDlg::OnBnClickedBtnCreate()
{
    // TODO: 创建驱动的调用
    hDriver = CreateFile(
        DRIVER_SYMBOLLINK_NAME,
        GENERIC_WRITE | GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    if ((DWORD)hDriver != 0xFFFFFFFF)
    {
        TRACE("JJR:R3 获取驱动句柄成功:0x%08X", hDriver);
    }
}
 
// 结束驱动调用
void CR3AppForMyDriverDlg::OnBnClickedBtnClose()
{
    // TODO: 结束驱动的调用
    if ((DWORD)hDriver != 0xFFFFFFFF)
    {
        CloseHandle(hDriver);
        TRACE("JJR:R3 结束对驱动调用成功");
        hDriver = (HANDLE)0xFFFFFFFF;
    }
}

实现驱动层(R0)和用户层(R3)通信,是实现用户层对驱动层控制的重要方式,实现驱动层与用户层通信可以使用以下API 函数:

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
BOOL WriteFile(
  HANDLE hFile,                    // 句柄
  LPCVOID lpBuffer,                // 缓冲区
  DWORD nNumberOfBytesToWrite,     // 缓冲区大小
  LPDWORD lpNumberOfBytesWritten,  // 实际写入的字节数
  LPOVERLAPPED lpOverlapped        // OVERLAPPED 结构指针
);
 
BOOL ReadFile(
  HANDLE hFile,                // 句柄
  LPVOID lpBuffer,             // 缓冲区
  DWORD nNumberOfBytesToRead,  // 缓冲区大小
  LPDWORD lpNumberOfBytesRead, // 实际读取的字节数
  LPOVERLAPPED lpOverlapped    // OVERAPPED 结构指针
);
 
BOOL WINAPI DeviceIoControl(
  __in         HANDLE hDevice,// 需要执行操作的句柄
  __in         DWORD dwIoControlCode,// 操作的控制代码。
  // 该值标识要执行的特定操作以及要在其上执行的设备的类型
  __in_opt     LPVOID lpInBuffer,// 指向包含执行操作所需
  // 的数据的输入缓冲区的指针
  __in         DWORD nInBufferSize,// 输入缓冲区的大小,
  // 以字节为单位。
  __out_opt    LPVOID lpOutBuffer,// 指向要接收操作返回的
  // 数据的输出缓冲区的指针
  __in         DWORD nOutBufferSize,// 输出缓冲区的大小,
  // 以字节为单位。
  __out_opt    LPDWORD lpBytesReturned,// 指向变量的指针,
  // 该变量接收以字节为单位的输出缓冲区中存储的数据大小.
  __inout_opt  LPOVERLAPPED lpOverlapped //指向OVERLAPPED
  // 结构的指针。
);
  1. 使用DeviceIoControl 函数实现用户层与驱动通信:
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
/**********************驱动层代码*************************/
// 驱动头文件
#include <ntddk.h>
 
// 驱动名称格式\\DEVICE\\YOUR_DEVICE_NAME
#define DEVICE_NAME L"\\device\\MyDevice"
// 驱动链接名称,格式为\\??\\YOUR_SYMBOLLINK_NAME
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
 
#define IO_TEST_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
 
 
// 驱动派遣回调函数
NTSTATUS DriverIRPCtrl(PDEVICE_OBJECT obj, PIRP pIrp)
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 当前IO 栈,用于存放用户层调用时产生的IRP 事件
    PIO_STACK_LOCATION pIoStackLocation = NULL;
    // 获取用户层调用时产生的IRP 函数
    pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
    // 判断IRP 事件类型
    switch (pIoStackLocation->MajorFunction)
    {
        case IRP_MJ_CREATE:
        {
            // 用户层使用CreateFile 调用驱动
            KdPrint(("JJR:用户层调用CreateFile 开启对驱动的调用"));
 
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
        case IRP_MJ_CLOSE:
        {
            // 用户层使用CloseHandle 结束驱动调用
            KdPrint(("JJR:用户层调用CLoseHandle 结束对驱动的调用"));
 
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
        case IRP_MJ_DEVICE_CONTROL:
        {
            // 获取控制码
            ULONG funcCode = pIoStackLocation->Parameters.DeviceIoControl.IoControlCode;
            if (funcCode == IO_TEST_CODE)
            {
                KdPrint(("JJR:用户层调用了DeviceIoControl 函数"));
                // 取出传入的缓冲区数据和大小
                char* inBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer;
                KdPrint(("JJR:用户层传入数据:%s", inBuffer));
                // inBuffer 既是传入数据的缓冲区,也是传出数据的缓冲区
                strcpy(inBuffer, "驱动层传出数据");
            }
 
 
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            // 实际传出缓冲区的大小
            pIrp->IoStatus.Information = pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
 
 
 
        }; break;
 
        default:
            break;
    }
    KdPrint(("JJR:退出派遣函数"));
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return status;
}
 
 
void DriverUnload(PDRIVER_OBJECT obj)
{
    // 删除符号链接
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    IoDeleteSymbolicLink(&SymbolLinkName);
    // 删除驱动设备
    // 这里驱动对象所包含的设备对象与我们创建的设备对象是同一个对象
    IoDeleteDevice(obj->DeviceObject);
    KdPrint(("JJR:驱动卸载函数启动"));
}
 
// 为驱动创建设备对象
NTSTATUS createDevice(PDRIVER_OBJECT obj)
{
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    NTSTATUS status = STATUS_SUCCESS;
    // 初始化驱动设备名称
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 驱动对象
    DEVICE_OBJECT deviceObj;
    status = IoCreateDevice(
        obj,
        0x4,
        &deviceName,
        FILE_DEVICE_UNKNOWN,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &deviceObj
    );
    return status;
}
 
// 为驱动绑定符号链接
NTSTATUS createSymbolLink()
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    // 驱动设备名称
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    status = IoCreateSymbolicLink(&SymbolLinkName, &deviceName);
    return status;
 
}
 
// 驱动入口点
NTSTATUS DriverEntry(/*驱动对象*/ PDRIVER_OBJECT obj, /*驱动注册路径*/PUNICODE_STRING registePath)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("JJR:驱动安装函数启动"));
    // 指定卸载函数
    obj->DriverUnload = DriverUnload;
    // 为IRP 事件指定派遣函数,指定的派遣函数可以为不同的事件不同的函数
    // 当用户层调用CreateFile 函数时产生的IRP 事件
    obj->MajorFunction[IRP_MJ_CREATE] = DriverIRPCtrl;
    // 当用户层调用CloseHandle 函数时产生的IRP 事件
    obj->MajorFunction[IRP_MJ_CLOSE] = DriverIRPCtrl;
    obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIRPCtrl;
 
    if (createDevice(obj) == STATUS_SUCCESS)
    {
        KdPrint(("JJR:驱动设备创建成功"));
        if (createSymbolLink() == STATUS_SUCCESS)
        {
            KdPrint(("JJR:驱动符号链接创建成功"));
        }
    }
    return status;
}
 
 
 
 
 
 
/**********************用户层代码*************************/
#include <winioctl.h>
// 定义的控制码
#define IO_TEST_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
void CR3AppForMyDriverDlg::OnBnClickedBtnMsgDevicecontrol()
{
    // TODO: 使用Devicecontrol 实现驱动层和用户层通信
    UpdateData(TRUE);
 
    TRACE("JJR:%s", CStringToPChar(m_R0Text));
    TRACE("JJR:%s", CStringToPChar(m_R3Text));
    char szpTest[256] = { 0 };
    strcpy_s(szpTest, sizeof(szpTest), CStringToPChar(m_R3Text));
    char szpResult[256] = { 0 };
    DWORD nSize = 0;
    if ((DWORD)hDriver != 0xFFFFFFFF)
    {
        if (DeviceIoControl(
            hDriver,
            IO_TEST_CODE,
            szpTest,
            sizeof(szpTest),
            szpResult,
            sizeof(szpResult),
            &nSize,
            NULL
        ))
        {
            m_R0Text = PCharToCString(szpResult);
            UpdateData(FALSE);
        }
    }
 
}
  1. 使用WriteFile 函数和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
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
215
216
217
218
/**********************驱动层代码*************************/
// 驱动头文件
#include <ntddk.h>
 
// 驱动名称格式\\DEVICE\\YOUR_DEVICE_NAME
#define DEVICE_NAME L"\\device\\MyDevice"
// 驱动链接名称,格式为\\??\\YOUR_SYMBOLLINK_NAME
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
 
#define IO_TEST_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
 
 
// 驱动派遣回调函数
NTSTATUS DriverIRPCtrl(PDEVICE_OBJECT obj, PIRP pIrp)
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 当前IO 栈,用于存放用户层调用时产生的IRP 事件
    PIO_STACK_LOCATION pIoStackLocation = NULL;
    // 获取用户层调用时产生的IRP 函数
    pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
    // 判断IRP 事件类型
    switch (pIoStackLocation->MajorFunction)
    {
        case IRP_MJ_CREATE:
        {
            // 用户层使用CreateFile 调用驱动
            KdPrint(("JJR:用户层调用CreateFile 开启对驱动的调用"));
 
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
        case IRP_MJ_CLOSE:
        {
            // 用户层使用CloseHandle 结束驱动调用
            KdPrint(("JJR:用户层调用CLoseHandle 结束对驱动的调用"));
 
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
        case IRP_MJ_DEVICE_CONTROL:
        {
            // 获取控制码
            ULONG funcCode = pIoStackLocation->Parameters.DeviceIoControl.IoControlCode;
            if (funcCode == IO_TEST_CODE)
            {
 
                KdPrint(("JJR:用户层调用了DeviceIoControl 函数"));
                // 取出传入的缓冲区数据和大小
                char* inBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer;
                KdPrint(("JJR:用户层传入数据:%s", inBuffer));
                // inBuffer 既是传入数据的缓冲区,也是传出数据的缓冲区
                strcpy(inBuffer, "驱动层传出数据");
            }
 
 
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            // 实际传出缓冲区的大小
            pIrp->IoStatus.Information = pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
 
 
 
        }; break;
        case IRP_MJ_WRITE:
        {
            KdPrint(("JJR:用户层调用了WriteFile 函数"));
            char* inBuffer = (char*)pIrp->UserBuffer;
            KdPrint(("JJR:传递的数据>> %s", inBuffer));
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
        case IRP_MJ_READ:
        {
            KdPrint(("JJR:用户层调用了ReadFile 函数"));
            char* inBuffer = (char*)pIrp->UserBuffer;
            KdPrint(("JJR:传递的数据>> %s", inBuffer));
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }
 
        default:
            break;
    }
    KdPrint(("JJR:退出派遣函数"));
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return status;
}
 
 
void DriverUnload(PDRIVER_OBJECT obj)
{
    // 删除符号链接
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    IoDeleteSymbolicLink(&SymbolLinkName);
    // 删除驱动设备
    // 这里驱动对象所包含的设备对象与我们创建的设备对象是同一个对象
    IoDeleteDevice(obj->DeviceObject);
    KdPrint(("JJR:驱动卸载函数启动"));
}
 
// 为驱动创建设备对象
NTSTATUS createDevice(PDRIVER_OBJECT obj)
{
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    NTSTATUS status = STATUS_SUCCESS;
    // 初始化驱动设备名称
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 驱动对象
    DEVICE_OBJECT deviceObj;
    status = IoCreateDevice(
        obj,
        0x4,
        &deviceName,
        FILE_DEVICE_UNKNOWN,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &deviceObj
    );
    return status;
}
 
// 为驱动绑定符号链接
NTSTATUS createSymbolLink()
{
    NTSTATUS status = STATUS_SUCCESS;
 
    // 符号链接名称
    UNICODE_STRING SymbolLinkName;
    RtlInitUnicodeString(&SymbolLinkName, DRIVER_SYMBOLLINK_NAME);
    // 驱动设备名称
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    status = IoCreateSymbolicLink(&SymbolLinkName, &deviceName);
    return status;
 
}
 
// 驱动入口点
NTSTATUS DriverEntry(/*驱动对象*/ PDRIVER_OBJECT obj, /*驱动注册路径*/PUNICODE_STRING registePath)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("JJR:驱动安装函数启动"));
    // 指定卸载函数
    obj->DriverUnload = DriverUnload;
    // 为IRP 事件指定派遣函数,指定的派遣函数可以为不同的事件不同的函数
    // 当用户层调用CreateFile 函数时产生的IRP 事件
    obj->MajorFunction[IRP_MJ_CREATE] = DriverIRPCtrl;
    // 当用户层调用CloseHandle 函数时产生的IRP 事件
    obj->MajorFunction[IRP_MJ_CLOSE] = DriverIRPCtrl;
    obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIRPCtrl;
    obj->MajorFunction[IRP_MJ_WRITE] = DriverIRPCtrl;
    obj->MajorFunction[IRP_MJ_READ] = DriverIRPCtrl;
 
    if (createDevice(obj) == STATUS_SUCCESS)
    {
        KdPrint(("JJR:驱动设备创建成功"));
        if (createSymbolLink() == STATUS_SUCCESS)
        {
            KdPrint(("JJR:驱动符号链接创建成功"));
        }
    }
    return status;
}
 
/**********************用户层代码*************************/
void CR3AppForMyDriverDlg::OnBnClickedBtnMsgWritefile()
{
    // TODO: 使用WriteFile 向驱动层通信
    UpdateData(TRUE);
 
    char szpTest[256] = { 0 };
    strcpy_s(szpTest, sizeof(szpTest), CStringToPChar(m_R3Text));
    char szpResult[256] = { 0 };
    DWORD nSize = 0;
    if ((DWORD)hDriver != 0xFFFFFFFF)
    {
        if (WriteFile(
            hDriver,
            szpTest,
            strlen(szpTest),
            &nSize,
            NULL
        ))
        {
            TRACE("JJR:执行成功");
        }
    }
 
 
}
 
 
void CR3AppForMyDriverDlg::OnBnClickedBtnMsgReadfile()
{
    // TODO: 使用WriteFile 向驱动层通信
    UpdateData(TRUE);
 
    char szpTest[256] = { 0 };
    strcpy_s(szpTest, sizeof(szpTest), CStringToPChar(m_R3Text));
    char szpResult[256] = { 0 };
    DWORD nSize = 0;
    if ((DWORD)hDriver != 0xFFFFFFFF)
    {
        if (ReadFile(
            hDriver,
            szpTest,
            strlen(szpTest),
            &nSize,
            NULL
        ))
        {
            TRACE("JJR:执行成功");
        }
    }
}

驱动学习6--驱动的加载执行和停止卸载

驱动在调用过程中使用的InsDrv.exe 工具实现安装驱动、开启驱动、停止驱动和卸载驱动,但是在正常的执行过程中,上述步骤是放在代码中来实现的。

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
#include <winsvc.h>
 
// 安装驱动
BOOL installDvr(CONST WCHAR drvPath[50], CONST WCHAR serviceName[20]) {
 
    // 打开服务控制管理器数据库
    SC_HANDLE schSCManager = OpenSCManager(
        NULL,                   // 目标计算机的名称,NULL:连接本地计算机上的服务控制管理器
        NULL,                   // 服务控制管理器数据库的名称,NULL:打开 SERVICES_ACTIVE_DATABASE 数据库
        SC_MANAGER_ALL_ACCESS   // 所有权限
    );
    if (schSCManager == NULL) {
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    // 创建服务对象,添加至服务控制管理器数据库
    SC_HANDLE schService = CreateService(
        schSCManager,               // 服务控件管理器数据库的句柄
        serviceName,                // 要安装的服务的名称
        serviceName,                // 用户界面程序用来标识服务的显示名称
        SERVICE_ALL_ACCESS,         // 对服务的访问权限:所有全权限
        SERVICE_KERNEL_DRIVER,      // 服务类型:驱动服务
        SERVICE_DEMAND_START,       // 服务启动选项:进程调用 StartService 时启动
        SERVICE_ERROR_IGNORE,       // 如果无法启动:忽略错误继续运行
        drvPath,                    // 驱动文件绝对路径,如果包含空格需要多加双引号
        NULL,                       // 服务所属的负载订购组:服务不属于某个组
        NULL,                       // 接收订购组唯一标记值:不接收
        NULL,                       // 服务加载顺序数组:服务没有依赖项
        NULL,                       // 运行服务的账户名:使用 LocalSystem 账户
        NULL                        // LocalSystem 账户密码
    );
    if (schService == NULL) {
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    return TRUE;
}
 
// 启动服务
BOOL startDvr(CONST WCHAR serviceName[20]) {
 
    // 打开服务控制管理器数据库
    SC_HANDLE schSCManager = OpenSCManager(
        NULL,                   // 目标计算机的名称,NULL:连接本地计算机上的服务控制管理器
        NULL,                   // 服务控制管理器数据库的名称,NULL:打开 SERVICES_ACTIVE_DATABASE 数据库
        SC_MANAGER_ALL_ACCESS   // 所有权限
    );
    if (schSCManager == NULL) {
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    // 打开服务
    SC_HANDLE hs = OpenService(
        schSCManager,           // 服务控件管理器数据库的句柄
        serviceName,            // 要打开的服务名
        SERVICE_ALL_ACCESS      // 服务访问权限:所有权限
    );
    if (hs == NULL) {
        CloseServiceHandle(hs);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
    if (StartService(hs, 0, 0) == 0) {
        CloseServiceHandle(hs);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
 
    CloseServiceHandle(hs);
    CloseServiceHandle(schSCManager);
    return TRUE;
}
 
// 停止服务
BOOL stopDvr(CONST WCHAR serviceName[20]) {
 
    // 打开服务控制管理器数据库
    SC_HANDLE schSCManager = OpenSCManager(
        NULL,                   // 目标计算机的名称,NULL:连接本地计算机上的服务控制管理器
        NULL,                   // 服务控制管理器数据库的名称,NULL:打开 SERVICES_ACTIVE_DATABASE 数据库
        SC_MANAGER_ALL_ACCESS   // 所有权限
    );
    if (schSCManager == NULL) {
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    // 打开服务
    SC_HANDLE hs = OpenService(
        schSCManager,           // 服务控件管理器数据库的句柄
        serviceName,            // 要打开的服务名
        SERVICE_ALL_ACCESS      // 服务访问权限:所有权限
    );
    if (hs == NULL) {
        CloseServiceHandle(hs);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    // 如果服务正在运行
    SERVICE_STATUS status;
    if (QueryServiceStatus(hs, &status) == 0) {
        CloseServiceHandle(hs);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
//    typedef struct _SERVICE_STATUS {
//    /* 服务指向文件的类型 */   
//        DWORD dwSesservirviceType;
//    /* 用于通知SCM(服务控制管理器)此服务的现行状态 */   
//        DWORD dwCurrentState;
//    /* 指明服务接受什么样的控制通知 */   
//        DWORD dwControlsAccepted;
//    /* 服务用于报告启动或停止时发生的错误的错误代码 */   
//        DWORD dwWin32ExitCode;
//    /* 服务特定的错误代码,服务在启动或停止时发生错误时,该服务将返回 */   
//        DWORD dwServiceSpecificExitCode;
//    /* 服务的检查点值会定期增加,以在长时间的启动,停止,暂停或继续操作期间报告其进度 */   
//        DWORD dwCheckPoint;
//    /* 挂起的启动,停止,暂停或继续操作所需的估计时间,以毫秒为单位 */   
//        DWORD dwWaitHint;
//    } SERVICE_STATUS, *LPSERVICE_STATUS;
 
    if (status.dwCurrentState != SERVICE_STOPPED &&    
        status.dwCurrentState != SERVICE_STOP_PENDING
        ) {
        // 发送关闭服务请求
        if (ControlService(
            hs,                         // 服务句柄
            SERVICE_CONTROL_STOP,       // 控制码:通知服务应该停止
            &status                     // 接收最新的服务状态信息
        ) == 0) {
            CloseServiceHandle(hs);
            CloseServiceHandle(schSCManager);
            return FALSE;
        }
 
        // 判断超时
        INT timeOut = 0;
        while(status.dwCurrentState != SERVICE_STOPPED){
            timeOut++;
            QueryServiceStatus(hs, &status);
            Sleep(50);
        }
        if (timeOut > 80) {
            CloseServiceHandle(hs);
            CloseServiceHandle(schSCManager);
            return FALSE;
        }
    }
 
    CloseServiceHandle(hs);
    CloseServiceHandle(schSCManager);
    return TRUE;
}
 
// 卸载驱动
BOOL unloadDvr(CONST WCHAR serviceName[20]) {
 
    // 打开服务控制管理器数据库
    SC_HANDLE schSCManager = OpenSCManager(
        NULL,                   // 目标计算机的名称,NULL:连接本地计算机上的服务控制管理器
        NULL,                   // 服务控制管理器数据库的名称,NULL:打开 SERVICES_ACTIVE_DATABASE 数据库
        SC_MANAGER_ALL_ACCESS   // 所有权限
    );
    if (schSCManager == NULL) {
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    // 打开服务
    SC_HANDLE hs = OpenService(
        schSCManager,           // 服务控件管理器数据库的句柄
        serviceName,            // 要打开的服务名
        SERVICE_ALL_ACCESS      // 服务访问权限:所有权限
    );
    if (hs == NULL) {
        CloseServiceHandle(hs);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    // 删除服务
    if (DeleteService(hs) == 0) {
        CloseServiceHandle(hs);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }
 
    CloseServiceHandle(hs);
    CloseServiceHandle(schSCManager);
    return TRUE;
}

驱动学习7--SSDT HOOK(x86 架构下)

SSDT 的全称是System Services Descriptor Table, 系统服务描述表。这个表就是一个吧Ring3 的Win32 API 和Ring0 内核API 联系起来。
SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含一些其他应用的信息,如:地址索引的基址、服务函数个数等。
通过修改此表的函数地址可以对常用的Windows 函数及API 进行HOOK,从而实现对一些关心的系统动作进行过滤、监控的目的。一些HIPS(主机入侵防御系统)、防毒软件、系统监控、注册表监控软件往往会采用此接口来实现自己的监控模块。
SSDT 即系统服务描述表,它的结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// KSYSTEM_SERVICE_TABLE 和 KSERVICE_TABLE_DESCRIPTOR
// 用来定义 SSDT 结构
typedef struct _KSYSTEM_SERVICE_TABLE
{
    PULONG  ServiceTableBase;                               // SSDT (System Service Dispatch Table)的基地址
    PULONG  ServiceCounterTableBase;                        // 用于 checked builds, 包含 SSDT 中每个服务被调用的次数
    ULONG   NumberOfService;                                // 服务函数的个数, NumberOfService * 4 就是整个地址表的大小
    ULONG   ParamTableBase;                                 // SSPT(System Service Parameter Table)的基地址
} KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE;
 
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
    KSYSTEM_SERVICE_TABLE   ntoskrnl;                       // ntoskrnl.exe 的服务函数
    KSYSTEM_SERVICE_TABLE   win32k;                         // win32k.sys 的服务函数(GDI32.dll/User32.dll 的内核支持)
    KSYSTEM_SERVICE_TABLE   notUsed1;
    KSYSTEM_SERVICE_TABLE   notUsed2;
}KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;

内核中有两个系统服务描述符表,一个是KeServiceDescriptorTable(由ntoskrnl.exe导出),一个是KeServieDescriptorTableShadow(没有导出)。
两者的区别是,KeServiceDescriptorTable仅有ntoskrnel一项,KeServieDescriptorTableShadow包含了ntoskrnel以及win32k。一般的Native API(原生API)的服务地址由KeServiceDescriptorTable分派,gdi.dll/user.dll的内核API调用服务地址由KeServieDescriptorTableShadow分派。还有要清楚一点的是win32k.sys只有在GUI线程中才加载,一般情况下是不加载的,所以要Hook KeServieDescriptorTableShadow的话,一般是用一个GUI程序通过IoControlCode来触发(想当初不明白这点,蓝屏死机了N次都想不明白是怎么回事)。(此段摘抄自网络)
内核HOOK 分类:

 

图片描述

SSDT HOOK 原理:

  1. 首先是关于内核函数地址是怎么计算的。这里以NtOpenProcess 为例:
    首先是要IDA 加载ntdll.dll, 查找NtOpenProcess 查看函数对应的SystemId,这个值可以理解为地址表内的一个下标。
    图片描述

  2. 查看KeServiceDescriptorTable(服务描述表):
    是要WinDbg 调试本地内核或者双调试,执行命令

    1
    dd KeServiceDescriptorTable

    图片描述
    所得到的0x83EBDD9C 值就指向函数表首地址的指针,如下:
    图片描述

  3. 利用函数表首地址和SystemId(下标)计算出目标函数 (NtOpenProcess)函数对应的地址。

    1
    pKernelFuncAddress = [[KeServiceDescriptorTable] + SystenId*0x4]

    图片描述
    上述就是计算NtOpenProcess 函数地址的方式。那么样实现HOOK 该函数,就是将最后得出的地址0x840529DC 替换成自己的函数地址。

参考文章:

https://bbs.pediy.com/thread-40832.htm

实现对SSDT 表的修改,首先要确保这个表示可写的。可以通过以下3种方法实现对SSDT 的内存保护机制的修改。
修改方式:

  1. 修改注册表

    1
    2
    恢复页面保护:HKLM\SYSTEM\CurrentControlset\Control\Session Manger\Memory Management\EnforceWriteProtection=0
    去掉页面保护:HKLM\SYSTEM\CurrentControlset\Control\Session Manger\Memory Management\DisablePagingExecutive=1
  2. 改变CR0 寄存器的第一位
    Windows对内存的分配,是采用的分页管理。其中有个CR0寄存器,如下图:
    图片描述
    其中第一位叫做保护属性位,控制着页的读写属性。如果为1,则页面可进行读写和执行,如果为0,则只能进行读和执行操作。SSDT, IDT 的页属性默认情况下是只读可执行的。

    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
    //设置为不可写
    void DisableWrite()
    {
        __try
        {
            _asm
            {
                mov eax, cr0
                or  eax, 10000h
                mov cr0, eax
                sti
            }
        }
        __except(1)
        {
            KdPrint(("DisableWrite执行失败!"));
        }
    }
    // 设置为可写
    void EnableWrite()
    {
        __try
        {
            _asm
            {
                cli
                mov eax,cr0
                and eax,not 10000h //and eax,0FFFEFFFFh
                mov cr0,eax
            }
        }
        __except(1)
        {
            KdPrint(("EnableWrite执行失败!"));
        }
    }

    //设置为不可写
    void DisableWrite()
    {
    __try
    {

    1
    2
    3
    4
    5
    6
    7
    _asm
    {
        mov eax, cr0
        or  eax, 10000h
        mov cr0, eax
        sti
    }

    }
    __except(1)
    {

    1
    KdPrint(("DisableWrite执行失败!"));

    }
    }
    // 设置为可写
    void EnableWrite()
    {
    __try
    {

    1
    2
    3
    4
    5
    6
    7
    _asm
    {
        cli
        mov eax,cr0
        and eax,not 10000h //and eax,0FFFEFFFFh
        mov cr0,eax
    }

    }
    __except(1)
    {

    1
    KdPrint(("EnableWrite执行失败!"));

    }
    }

  3. 第三种方法就是使用Memory Descriptor List(MDL)。
    获取SSDT 中函数的地址的方式:
    获取SSDT 内函数的地址需要使用到两个宏,分别是
    1
    2
    指定服务的索引:SYSCALL_INDEX
    指定服务的当前地址:SYSCALL_FUNCTION
    定义如下:
    1
    2
    3
    4
    //根据 ZwServiceFunction 获取 ZwServiceFunction 在 SSDT 中所对应的服务的索引号
    #define SYSCALL_INDEX(ServiceFunction) (*(PULONG)((PUCHAR)ServiceFunction + 1))
    //根据ZwServiceFunction 来获得服务在 SSDT 中的索引号,然后再通过该索引号来获取ntServiceFunction的地址
    #define SYSCALL_FUNCTION(ServiceFunction) KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[SYSCALL_INDEX(ServiceFunction)]
    SSDT HOOK 流程:
    图片描述
    在驱动函数的入口函数中,对未进行SSDT HOOK 前SSDT 表进行备份(使用数组保存)。备份时,一个索引号对应一个当前地址。
    在卸载HOOK 的时候,就可以从全局数组中根据索引号恢复位HOOK 前的服务名的当前地址。

SSDT HOOK 代码框架

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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#include <ntddk.h>
 
#define IO_TEST_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
 
 
 
 
 
void BackupSysServiceTable();
NTSTATUS installHook(ULONG oldService, ULONG newService);
NTSTATUS unstallHook(ULONG oldService);
NTSTATUS MyNtTerminateProcess(__in_opt HANDLE ProcessHandle, __in NTSTATUS ExitStatus);
void DisableWrite();
void EnableWrite();
NTSTATUS CreateSymbolicLinkFunc();
NTSTATUS CreateDeviceFunc(PDRIVER_OBJECT obj);
void DriverUnloadFunc(PDRIVER_OBJECT obj);
NTSTATUS DriverEntry(PDRIVER_OBJECT obj, PUNICODE_STRING path);
 
 
 
// 设备名称
#define DEVICE_NAME L"\\DEVICE\\HOOKDEVICE"
 
// 符号链接名称
#define SYMBOLLINK_NAME L"\\??\\HOOKSYSMBOLLINKNAME"
 
// KSYSTEM_SERVICE_TABLE 和 KSERVICE_TABLE_DESCRIPTOR
// 用来定义 SSDT 结构
typedef struct _KSYSTEM_SERVICE_TABLE
{
    PULONG  ServiceTableBase;                               // SSDT (System Service Dispatch Table)的基地址
    PULONG  ServiceCounterTableBase;                        // 用于 checked builds, 包含 SSDT 中每个服务被调用的次数
    ULONG   NumberOfService;                                // 服务函数的个数, NumberOfService * 4 就是整个地址表的大小
    ULONG   ParamTableBase;                                 // SSPT(System Service Parameter Table)的基地址
} KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE;
 
//一个为导出的结构体
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
    KSYSTEM_SERVICE_TABLE   ntoskrnl;                       // ntoskrnl.exe 的服务函数
    KSYSTEM_SERVICE_TABLE   win32k;                         // win32k.sys 的服务函数(GDI32.dll/User32.dll 的内核支持)
    KSYSTEM_SERVICE_TABLE   notUsed1;
    KSYSTEM_SERVICE_TABLE   notUsed2;
}KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
 
// 定义KeServiceDescriptorTable, 需要导出
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
 
// 用于获取SSDT 中函数的地址
// 根据 ZwServiceFunction 获取 ZwServiceFunction 在 SSDT 中所对应的服务的索引号
#define SYSCALL_INDEX(ServiceFunction) (*(PULONG)((PUCHAR)ServiceFunction + 1))
// 根据 ZwServiceFunction 来获得服务在 SSDT 中的索引号,然后再通过该索引号来获取 ntServiceFunction的地址
#define SYSCALL_FUNCTION(ServiceFunction) KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[SYSCALL_INDEX(ServiceFunction)]
 
 
#define MAX_INDEX_NUM 1024
 
// 用来保存SSDT 中所有的旧的服务函数的地址
ULONG oldSysServiceAddr[MAX_INDEX_NUM] = { 0 };
 
 
// 待HOOK 函数的函数指针
typedef NTSTATUS(*NTTERMINATEPROCESS)(__in_opt HANDLE ProcessHandle, __in NTSTATUS ExitStatus);
NTTERMINATEPROCESS pOldNtTerminateProcess;
 
typedef NTSTATUS(*NTOPENPROCESS)(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
    );
 
NTOPENPROCESS pOldNtOpenProcess;
 
// 自定义函数
/*****************************************************************/
NTSTATUS MyNtTerminateProcess(__in_opt HANDLE ProcessHandle, __in NTSTATUS ExitStatus)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("退出不了了吧,哈哈哈哈哈哈哈哈哈:%X", pOldNtTerminateProcess));
    pOldNtTerminateProcess = (NTTERMINATEPROCESS)oldSysServiceAddr[SYSCALL_INDEX(ZwTerminateProcess)];
    status = pOldNtTerminateProcess(ProcessHandle, ExitStatus);
    return status;
}
 
NTSTATUS MyNtOpenProcess(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID ClientId
){
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("打开进程"));
    pOldNtOpenProcess = (NTOPENPROCESS)oldSysServiceAddr[SYSCALL_INDEX(ZwOpenProcess)];
    status = pOldNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
    return status;
}
 
/*****************************************************************/
 
 
void BackupSysServiceTable()
{
 
    ULONG i;
    for (i = 0; (i < KeServiceDescriptorTable->ntoskrnl.NumberOfService) && (i < MAX_INDEX_NUM); i++)
    {
        // 备份原始函数表
        oldSysServiceAddr[i] = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[i];
        KdPrint(("\n备份的函数表{ Number: 0x%04X , Address: %08X}", i, oldSysServiceAddr[i]));
    }
}
 
 
 
NTSTATUS installHook(ULONG oldService, ULONG newService)
{
    NTSTATUS status = STATUS_SUCCESS;
    __try
    {
        ULONG uOldAddr = 0;
        // 去除页面保护
        KdPrint(("伪装的NtTerminateProcess 地址:%X\r\n", (int)newService));
        KdPrint(("真实的NtTerminateProcess 地址:%X\r\n", (int)oldService));
        // 写入HOOK 的回调函数地址
        SYSCALL_FUNCTION(oldService) = newService;
        // 恢复页面包含
        DisableWrite();
        return status;
    }
    __except (1)
    {
        KdPrint(("安装Hook 失败"));
    }
 
    return status;
}
 
NTSTATUS unstallHook(ULONG oldService)
{
    KdPrint(("解除HOOK"));
    NTSTATUS status = STATUS_SUCCESS;
    __try
    {
        EnableWrite();    //去掉页面保护
        // 做一个判断,判断指定位置的地址是否是原地址而不是自定义函数的地址
        KdPrint(("当前HOOK 位置的地址:%X\t备份的地址:%X", SYSCALL_FUNCTION(oldService), oldSysServiceAddr[SYSCALL_INDEX(oldService)]));
        for (UINT32 i = 0; TRUE; i++)
        {
            KdPrint(("解除>>当前HOOK 位置的地址:%X\t备份的地址:%X", SYSCALL_FUNCTION(oldService), oldSysServiceAddr[SYSCALL_INDEX(oldService)]));
            if (SYSCALL_FUNCTION(oldService) != oldSysServiceAddr[SYSCALL_INDEX(oldService)])
            {
                SYSCALL_FUNCTION(oldService) = oldSysServiceAddr[SYSCALL_INDEX(oldService)];
            }
            else
            {
                break;
            }
        }
        KdPrint(("当前HOOK 位置的地址:%X\t备份的地址:%X", SYSCALL_FUNCTION(oldService), oldSysServiceAddr[SYSCALL_INDEX(oldService)]));
        DisableWrite();    //恢复页面保护
        return status;
    }
    __except (1)
    {
        KdPrint(("卸载Hook 失败!"));
    }
    return status;
}
 
// 对页面保护属性的修改
// 设置为不可写
void DisableWrite()
{
    __try
    {
        _asm
        {
            mov eax, cr0
            or eax, 10000h
            mov cr0, eax
            sti
        }
    }
    __except (1)
    {
        DbgPrint("DisableWrite执行失败!");
    }
}
// 设置为可写
void EnableWrite()
{
    __try
    {
        _asm
        {
            cli
            mov eax, cr0
            and eax, not 10000h //and eax,0FFFEFFFFh
            mov cr0, eax
        }
    }
    __except (1)
    {
        DbgPrint("EnableWrite执行失败!");
    }
}
 
// 创建符号链接
NTSTATUS CreateSymbolicLinkFunc()
{
    NTSTATUS status = STATUS_SUCCESS;
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 定义符号链接对象名称
    UNICODE_STRING symbolLinkName;
    RtlInitUnicodeString(&symbolLinkName, SYMBOLLINK_NAME);
    // 创建符号链接
    status = IoCreateSymbolicLink(&symbolLinkName, &deviceName);
    return status;
}
 
// 创建设备
NTSTATUS CreateDeviceFunc(PDRIVER_OBJECT obj)
{
    NTSTATUS status = STATUS_SUCCESS;
    // 定义驱动对象名称
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);
    // 创建驱动对象
    DEVICE_OBJECT deviceObj;
    status = IoCreateDevice(obj, 0x4, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObj);
    return status;
}
 
void DriverUnloadFunc(PDRIVER_OBJECT obj)
{
    KdPrint(("驱动卸载"));
    // 删除符号链接
    UNICODE_STRING symbolLinkName;
    RtlInitUnicodeString(&symbolLinkName, SYMBOLLINK_NAME);
    IoDeleteSymbolicLink(&symbolLinkName);
    // 删除设备
    IoDeleteDevice(obj->DeviceObject);
    // 卸载HOOK
    unstallHook(/*新函数地址*/(ULONG)ZwOpenProcess);
}
 
// 驱动派遣函数
NTSTATUS DriverIRPCtrl(PDRIVER_OBJECT obj, PIRP pIrp)
{
    NTSTATUS status = STATUS_SUCCESS;
    // 当前IO 栈,用于存放用户层调用时产生的IRP 事件
    PIO_STACK_LOCATION pIoStackLocation = NULL;
    // 获取用户层调用时产生的IRP 函数
    pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
    // 判断IRP 事件类型
    switch (pIoStackLocation->MajorFunction)
    {
        case IRP_MJ_CREATE:
        {
            KdPrint(("用户层调用CreateFile 开启对驱动的调用"));
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
        case IRP_MJ_DEVICE_CONTROL:
        {
            // 获取控制码
            ULONG funcCode = pIoStackLocation->Parameters.DeviceIoControl.IoControlCode;
            switch (funcCode)
            {
                case IO_TEST_CODE:
                {
                    KdPrint(("JJR:用户层调用了DeviceIoControl 函数"));
                    // 取出传入的缓冲区数据和大小
                    char* inBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer;
                    KdPrint(("JJR:用户层传入数据:%s", inBuffer));
                    // inBuffer 既是传入数据的缓冲区,也是传出数据的缓冲区
                    strcpy(inBuffer, "驱动层传出数据");
                }; break;
            }
        }; break;
        case IRP_MJ_CLOSE:
        {
            KdPrint(("用户层调用CloseHandle 关闭对驱动的调用"));
            pIrp->IoStatus.Status = STATUS_SUCCESS;
            pIrp->IoStatus.Information = 4;
        }; break;
    }
 
    KdPrint(("JJR:退出派遣函数"));
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return status;
}
 
// 驱动入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT obj, PUNICODE_STRING path)
{
    NTSTATUS status = STATUS_SUCCESS;
    KdPrint(("驱动入口"));
    if (NT_SUCCESS(CreateDeviceFunc(obj)))
    {
        KdPrint(("创建符号链接完成"));
        if (NT_SUCCESS(CreateSymbolicLinkFunc()))
        {
            KdPrint(("创建符号链接完成"));
        }
    }
 
 
    // 备份
    BackupSysServiceTable();
    // 安装HOOK
    installHook(/*原函数地址*/(ULONG)ZwOpenProcess, /*新函数地址*/(ULONG)MyNtOpenProcess);
    obj->DriverUnload = DriverUnloadFunc;
    return status;
}

未完待续....


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞9
打赏
分享
最新回复 (16)
雪    币: 6750
活跃值: (3338)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
romobin 2021-2-16 16:44
2
0
太棒了 深刻学习 
雪    币: 24
活跃值: (286)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Railgun_ 2021-2-16 18:26
3
0

学习一下

最后于 2021-2-16 18:27 被Railgun_编辑 ,原因:
雪    币: 1859
活跃值: (2215)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
奋进的小杨 2021-3-13 15:33
4
0
师傅,资料课程可以分享一下吗?
雪    币: 614
活跃值: (630)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
熟悉而又陌生 2021-3-19 17:25
5
0
期待大佬继续更新
雪    币: 6494
活跃值: (3101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
htpidk 2021-4-17 12:14
6
0
mark收藏一下
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_python_215 2021-5-7 01:25
7
0

正好ssdt看得我一愣一愣的。。 多谢楼主的姿势输出

最后于 2021-5-7 01:26 被wx_python_215编辑 ,原因:
雪    币: 41
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zmz_up 2021-5-8 14:21
8
0
学习学习 期待大佬更新
雪    币: 1448
活跃值: (14586)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
SSH山水画 3 2021-5-8 16:37
9
0
这个顺序  海哥没错了
雪    币: 41
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zmz_up 2021-5-10 15:48
10
0
雪    币: 279
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小白C 2021-5-12 22:05
11
0
这教程爱了爱了
雪    币: 41
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zmz_up 2021-5-23 18:06
12
0
错误        C4235        使用了非标准扩展: 不支持在此结构上使用“__asm”关键字

这个怎么解决呀
雪    币: 41
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zmz_up 2021-5-25 14:19
13
0
zmz_up 错误 C4235 使用了非标准扩展: 不支持在此结构上使用“__asm”关键字 这个怎么解决呀
我的是x64的所以不能直接使用内连汇编。
萌新的疑问,现在大部分都是 x64的系统,x86的驱动是不是不能在 x64上运行。
雪    币: 835
活跃值: (612)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
stand ot law 2021-6-16 15:45
14
0
make
雪    币: 22
活跃值: (192)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mutiantong 2021-7-26 17:58
15
0
mark
雪    币: 199
活跃值: (161)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaosawan 2021-11-15 16:02
16
0
zmz_up 我的是x64的所以不能直接使用内连汇编。 萌新的疑问,现在大部分都是 x64的系统,x86的驱动是不是不能在 x64上运行。
我也想问这个问题
雪    币: 4
活跃值: (88)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
SM的缠绵 2022-3-3 21:47
17
0
收藏了,感谢大佬
游客
登录 | 注册 方可回帖
返回