设备对象
在内核开发时,消息被封装成另外一个结构体:IRP,英文全称:I/O Request Package。在窗口程序中,能够接收消息的只能是窗口对象。在内核中,能够接收IRP消息的只能是设备对象
//设备对象
PDEVICE_OBJECT pDeviceObj;
//设备名称
UNICODE_STRING Devicename;
RtlInitUnicodeString(&Devicename,L"\\Device\\MyDevice");
//创建设备
IoCreateDevice(
pDriver, //当前设备所属的驱动对象
0,
&Devicename, //设备对象的名称
FILE_DEVICE_UNKNOWN,//设备类型
FILE_DEVICE_SECURE_OPEN,
FALSE,//是否独占
&pDeviceObj //设备对象指针
);
数据交互的方式
//缓冲区读写方式 : 操作系统将应用程序提供的缓冲区的数据复制到内核模式下的地址中
pDeviceObj->Flags |= DO_BUFFERED_IO;
//直接读写方式 : 操作系统会将用户模式下的缓冲区锁住。然后操作系统将这段缓冲区在内核模式地址再次映射一遍。这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存。缺点就是要单独占用物理页面。
pDeviceObj->Flags |= DO_DIRECT_IO;
//其它方式 :派遣函数直接读写应用程序提供的缓冲区地址 (只有驱动程序与应用程序运行在相同线程上下文的情况下,才能使用这种方式。如果CPU中的任务切换了,即CR3切换掉了,在高2GB的驱动仍在使用该方式读取低2GB内存,导致读到的数据和实际不符,导致错误,故强烈不推荐此方式)
不需要设置
创建符号链接
设备名称的作用是给内核对象用的,如果要在3环访问,必须要有符号链接。其实就是一个别名,没有这个别名,在3环不可见
内核模式下,符号链接是以??\开头的,如C盘就是??\C:。而在用户模式下,则是以\.\开头的,如C盘就是\.\C:
//创建符号链接名称
RtlInitUnicodeString(&SymbolicLinkName,L"\\??\\MyTestDriver");//对应3环的 \\\\.\\MyTestDriver
//创建符号链接
IoCreateSymbolicLink(&SymbolicLinkName,&Devicename);
应用层通过CreateFile、ReadFile、WriteFile、CloseHandle等函数打开、从设备读取数据、向设备写入数据、关闭设备的时候,会使操作系统分别产生出IRP_MJ_CREATE、IRP_MJ_READ、IRP_MJ_WRITE、IRP_MJ_CLOSE等不同的IRP。值得注意的是,我们之前使用CreateFile这个东西只是为了创建文件,其实它的本质是与设备对象创建访问,我们3环程序想要通过符号链接与驱动建立通讯,就必须通过这个函数。
派遣函数
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; //这里由28个派遣函数,可以自己设置
} DRIVER_OBJECT;
//设置卸载函数
pDriverObject->DriverUnload = 卸载函数;
//设置派遣函数
pDriverObject->MajorFunction[IRP_MJ_CREATE] = 派遣函数1;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = 派遣函数2;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = 派遣函数3;
pDriverObject->MajorFunction[IRP_MJ_READ] = 派遣函数4;
pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = 派遣函数5;
pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = 派遣函数6;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = 派遣函数7;
pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = 派遣函数8;
pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = 派遣函数9;
派遣函数的格式
NTSTATUS MyDispatchFunction(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
//处理自己的业务……
//设置返回状态
pIrp->IoStatus.Status = STATUS_SUCCESS; //GetLastError 函数得到的就是该值
pIrp->IoStatus.Information = 0; //返回给3环多少数据 没有填0
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
删除符号链接和设备
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
//删除符号链接
IoDeleteSymbolicLink(&symbolLink);
//删除设备
IoDeleteDevice(devObj);
DbgPrint("卸载成功!!!\n");
}