windows内核研究(驱动开发-0环与3环的通信)
驱动开发
0环与3环的通信
设备对象
在之前开发窗口程序时,消息都是被封装成一个结构体(MSG),在内核开发时,消息被封装成另外一个结构体:IRP(I/O Request Package)
在窗口程序中,能够接收消息的只能是窗口对象,在内核中,能够接收IRP消息的只能是设备对象
创建设备对象
// 创建设备名称
UNICODE_STRING deviceName;
RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");/*
NTSTATUS IoCreateDevice([in] PDRIVER_OBJECT DriverObject, // 驱动对象[in] ULONG DeviceExtensionSize, // 指定要为设备对象的 设备扩展 分配的驱动程序确定字节数[in, optional] PUNICODE_STRING DeviceName, // 设备名称[in] DEVICE_TYPE DeviceType, // 设备类型[in] ULONG DeviceCharacteristics, // 设备特征[in] BOOLEAN Exclusive, // 指定设备对象是否表示 独占设备[out] PDEVICE_OBJECT *DeviceObject // 指向接收指向新创建的 DEVICE_OBJECT 结构的指针的变量的指针
);
*/// 创建设备对象
NTSTATUS ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
数据的交互方式
// 设置数据的交互方式
driverObject->Flags |= DO_BUFFERED_IO;
- 缓存区方式读写(DO_BUFFERED_IO):操作系统将应用程序提供缓冲区的数据复制到内核模式下的地址中
- 直接方式读写(DO_DIRECT_IO):操作系统会将用户模式下的缓冲区锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍,这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存(缺点就是要单独占用物理页面)
- 其他方式读写(在调用IoCreateDevice创建设备后对drivceObjcet->Flags既不设置DO_BUFFERED_IO也不设置DO_DIRECT_IO此时就是其它方式):在使用其他方式读写设备时,派遣函数直接读写应用程序提供的缓冲地址。在驱动程序中,直接操作应用程序的缓冲区是很危险的,只有驱动程序与应用程序运行在相同线程上下文的情况下,才能使用这种方式
IRP的类型
当应用层通过CreateFile,ReadFile,WriteFile,CloseHandle等函数打开,从设备读取数据,向设备写入数据,关闭设备的时候,会使操作系统系统产出不同的IRP_CREATE,IPR_MJ_READ,IRP_MJ_WRITE等IRP
其它类型
IRP类型 | 来源 |
---|---|
IRP_MJ_DEVICE_CONTROL | DeviceControl 函数会产生些IRP |
IRP_MJ_POWER | 在操作系统处理电源消息时,产生此IRP |
IRP_MJ_SHUTDOWN | 关闭系统前会产生些IRP |
IRP_MJ_DEVICE_CONTROL
才是我们Ring3与驱动交互的常规方式
测试代码
3环应用程序代码
#include<iostream>
#include<windows.h>#define IN_BUFFER_MAXLENGIT 0x10 // 输入缓存最大长度
#define OUT_BUFFER_MAXLENGTH 0x10 // 输出缓存最大长度
// 参数说明:1,设备类型,2,操作码,3,以什么方式进行访问,4,访问权限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define SYMBOLICLINK_NAME "\\\\.\\MyTestDriver"HANDLE g_hDriver;BOOL open(const CHAR* pLinkName) {TCHAR szBuffer[10] = { 0 };g_hDriver = CreateFileA(pLinkName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);DWORD errorCode = GetLastError();swprintf(szBuffer,sizeof(szBuffer),L"%d:\n",errorCode);if (g_hDriver != INVALID_HANDLE_VALUE)return TRUE;else return FALSE;
}/*
BOOL DeviceIoControl([in] HANDLE hDevice, 设备句柄[in] DWORD dwIoControlCode, 控制代码[in, optional] LPVOID lpInBuffer, 向0环传递的缓冲区的地址[in] DWORD nInBufferSize, 缓冲区的大小[out, optional] LPVOID lpOutBuffer, 向3还传递的缓冲区的地址[in] DWORD nOutBufferSize, 缓冲区的大小[out, optional] LPDWORD lpBytesReturned, 实际返回的长度(字节数)[in, out, optional] LPOVERLAPPED lpOverlapped
);
*/BOOL ioControl(DWORD dwIoCode,PVOID InBuffer,DWORD InBuffLen,PVOID OutBuff,DWORD OutBuffLen) { DWORD dw;DeviceIoControl(g_hDriver,dwIoCode,InBuffer,InBuffLen,OutBuff,OutBuffLen,&dw,NULL);return TRUE;
}int main() {DWORD dwInBuffer = 0x11112222;TCHAR szOutBuffer[OUT_BUFFER_MAXLENGTH] = { 0 };// 通过符号链接 打开设备if (open(SYMBOLICLINK_NAME)) {printf("open device success\n");}else {printf("open device failed\n");}ioControl(OPER2, &dwInBuffer, IN_BUFFER_MAXLENGIT, szOutBuffer, OUT_BUFFER_MAXLENGTH);CloseHandle(g_hDriver);system("pause");return 0;
}
0环驱动程序
#include <ntddk.h>#define DEVICE_NAME L"\\Device\\MyDevice"
// Ring3用CreateDevice打开设备时用 \\\\.\\MyTestDriver
#define SYMBOLICLINK_NAME L"\\??\\MyTestDriver"#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)// IRP_MJ_CREATE 处理函数
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj,PIRP pIrp) {DbgPrint("设备创建了...");// 设置返回状态pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_CLOSE 处理函数
NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {DbgPrint("设备关闭了...");// 设置返回状态pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_DEVICE_CONTROL 处理函数
NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {NTSTATUS stauts = STATUS_INVALID_DEVICE_REQUEST;PIO_STACK_LOCATION pIrpStack;ULONG uIoControlCode;PVOID pIoBuffer;ULONG uInLength;ULONG uOutLength;ULONG uRead;ULONG uWrite;// 设置临时变量的值uRead = 0;uWrite = 0x12345678;//获取IRP数据pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//获取控制码uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 获取缓冲区地址(输入和输出的缓冲区都是一个)pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;// Ring3 发送数据的长度uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// Ring0 发送数据的长度uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;pIrp->IoStatus.Information = 0;switch (uIoControlCode) {case OPER1:{DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 1");// 设置返回状态pIrp->IoStatus.Information = 1;stauts = STATUS_SUCCESS;break;}case OPER2:{DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 接收字节数:%d\n", uInLength);DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 输出字节数:%d\n", uOutLength);// 读缓存memcpy(&uRead,pIoBuffer,4);DbgPrint("调用IRP_MJ_DEVICE_CONTROL —> 2 地址:%llx",uRead);// 写缓存memcpy(pIoBuffer,&uWrite,4);// 设置返回状态pIrp->IoStatus.Information = 2;stauts = STATUS_SUCCESS;break;}}// 设置返回状态pIrp->IoStatus.Status = stauts;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;}// 卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("驱动被卸载了\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING reg_path) {NTSTATUS ntIoCreate = 0;PDEVICE_OBJECT pDeviceObject = NULL;UNICODE_STRING deviceName;UNICODE_STRING symbolicLinkName;// 创建设备名称RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");// 创建设备对象ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);if (ntIoCreate != STATUS_SUCCESS) {DbgPrint("设备对象创建失败!\n");return ntIoCreate;}// 设置数据的交互方式driverObject->Flags |= DO_BUFFERED_IO;// 创建符号链接名称(给Ring3访问)// Ring3用CreateFile打开设备时用 \\\\.\\MyTestDriverRtlInitUnicodeString(&symbolicLinkName, L"\\??\\MyTestDriver");// 创建符号链接ntIoCreate = IoCreateSymbolicLink(&symbolicLinkName, &deviceName);if(ntIoCreate != STATUS_SUCCESS) {DbgPrint("符号链接创建失败!\n"); IoDeleteDevice(pDeviceObject);return ntIoCreate;}// 设置派遣函数和卸载函数driverObject->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;driverObject->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceControlProc;driverObject->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
演示效果