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

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

2021-2-15 20:28
22646

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

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

创建驱动设备对象源码:

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

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

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

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

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

具体实现代码:

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

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

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

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

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

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

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

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

内核中有两个系统服务描述符表,一个是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 分类:

图片描述

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

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

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

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

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

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

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

修改注册表

改变CR0 寄存器的第一位
Windows对内存的分配,是采用的分页管理。其中有个CR0寄存器,如下图:
图片描述
其中第一位叫做保护属性位,控制着页的读写属性。如果为1,则页面可进行读写和执行,如果为0,则只能进行读和执行操作。SSDT, IDT 的页属性默认情况下是只读可执行的。

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

}
__except(1)
{

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

}
__except(1)
{

}
}

SSDT HOOK 代码框架

编写驱动前环境设置(仅为不使用框架时使用)
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. 属性 -> 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 : 否
// 驱动头文件
#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;
}
// 驱动头文件
#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;
}
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
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
// 驱动头文件
#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;
}
// 驱动头文件
#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;
}
NTSTATUS IoCreateSymbolicLink(
  PUNICODE_STRING SymbolicLinkName,// 符号链接名称,unicode 字符串
  PUNICODE_STRING DeviceName// 设备名称
);
NTSTATUS IoCreateSymbolicLink(
  PUNICODE_STRING SymbolicLinkName,// 符号链接名称,unicode 字符串
  PUNICODE_STRING DeviceName// 设备名称
);
// 驱动头文件
#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;
}
// 驱动头文件
#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;
}
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;
}
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;
}
obj->MajorFunction[IRP_MJ_CREATE] = DriverIRPCtl; // 指定驱动打开的派遣函数
obj->MajorFunction[IRP_MJ_CLOSE] = DriverIRPCtl; // 指定驱动关闭的派遣函数
// 派遣函数可以为多个,也可以指定应该。不同的是当指定应该函数时,需要
// 对传入的IRP 事件进行判断
obj->MajorFunction[IRP_MJ_CREATE] = DriverIRPCtl; // 指定驱动打开的派遣函数
obj->MajorFunction[IRP_MJ_CLOSE] = DriverIRPCtl; // 指定驱动关闭的派遣函数
// 派遣函数可以为多个,也可以指定应该。不同的是当指定应该函数时,需要
// 对传入的IRP 事件进行判断
// 驱动头文件
#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;
}
// 驱动头文件
#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;
}
obj->MajorFunction[IRP_TYPE] = FUNC;
obj->MajorFunction[IRP_TYPE] = FUNC;
HANDLE CreateFile(
  LPCTSTR lpFileName,          // 文件名称,这里指符号链接名称
  DWORD dwDesiredAccess,       // 读取权限
  DWORD dwShareMode,           // 共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                               // 安全属性
  DWORD dwCreationDisposition,  // 创建方式
  DWORD dwFlagsAndAttributes,  // 文件属性
  HANDLE hTemplateFile         // 复制文件所使用的句柄
);
HANDLE CreateFile(
  LPCTSTR lpFileName,          // 文件名称,这里指符号链接名称
  DWORD dwDesiredAccess,       // 读取权限
  DWORD dwShareMode,           // 共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                               // 安全属性
  DWORD dwCreationDisposition,  // 创建方式
  DWORD dwFlagsAndAttributes,  // 文件属性
  HANDLE hTemplateFile         // 复制文件所使用的句柄
);
BOOL CloseHandle(
  HANDLE hObject   // 对象句柄
);
BOOL CloseHandle(
  HANDLE hObject   // 对象句柄
);
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
// 驱动对象句柄
HANDLE hDriver = (HANDLE)0xFFFFFFFF;
#define DRIVER_SYMBOLLINK_NAME L"\\??\\MySymbolLinkName"
// 驱动对象句柄
HANDLE hDriver = (HANDLE)0xFFFFFFFF;
// 开始驱动调用
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;
    }
}
// 开始驱动调用
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;
    }
}
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
  // 结构的指针。
);
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
  // 结构的指针。
);
/**********************驱动层代码*************************/
// 驱动头文件
#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);
        }
    }
 
}
/**********************驱动层代码*************************/
// 驱动头文件
#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);
        }
    }
 
}
/**********************驱动层代码*************************/
// 驱动头文件
#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:执行成功");
        }
    }
}
/**********************驱动层代码*************************/
// 驱动头文件
#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:驱动卸载函数启动"));

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 10
支持
分享
最新回复 (16)
雪    币: 7979
活跃值: (4739)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
太棒了 深刻学习 
2021-2-16 16:44
0
雪    币: 24
活跃值: (286)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

学习一下

最后于 2021-2-16 18:27 被Railgun_编辑 ,原因:
2021-2-16 18:26
0
雪    币: 1859
活跃值: (2245)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
师傅,资料课程可以分享一下吗?
2021-3-13 15:33
0
雪    币: 1032
活跃值: (1203)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
期待大佬继续更新
2021-3-19 17:25
0
雪    币: 7379
活跃值: (4086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
mark收藏一下
2021-4-17 12:14
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7

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

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

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