内核中执行代码后需要将结果动态显示给应用层的用户,DeviceIoControl 是直接发送控制代码到指定的设备驱动程序,使相应的移动设备以执行相应的操作的函数,如下代码是一个经典的驱动开发模板框架,在开发经典驱动时会用到的一个通用案例。
一般要实现驱动程与应用层通信有多种方法,最简单的一种方式则是通过IO派遣实现,应用层通过DeviceIoControl
函数与内核建立联系,DeviceIoControl 是 Windows 操作系统提供的一个函数,用于与设备驱动程序进行通信。它允许应用程序发送控制代码(IOCTL)给设备驱动程序,并传递相应的输入和输出缓冲区。
该函数的原型如下:
BOOL DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped
);
参数说明:
- hDevice:设备句柄,用于标识要进行操作的设备。
- dwIoControlCode:控制代码,用于指定要执行的设备操作。
- lpInBuffer:输入缓冲区,包含要传递给设备的输入数据。
- nInBufferSize:输入缓冲区大小,以字节为单位。
- lpOutBuffer:输出缓冲区,用于接收设备返回的输出数据。
- nOutBufferSize:输出缓冲区大小,以字节为单位。
- lpBytesReturned:用于接收实际传输的字节数。
- lpOverlapped:用于异步操作的指针。
通过调用 DeviceIoControl
函数,应用程序可以向设备发送各种类型的请求,例如读取设备状态、执行设备操作、获取设备信息等。具体的操作和使用方式取决于所操作的设备驱动程序提供的功能。
驱动程序开发通用模板代码如下:
#include <ntifs.h>
#include <windef.h>// 控制器
#define IOCTL_IO_LyShark CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)// 卸载驱动执行
VOID UnDriver(PDRIVER_OBJECT pDriver)
{PDEVICE_OBJECT pDev; // 用来取得要删除设备对象UNICODE_STRING SymLinkName; // 局部变量symLinkNamepDev = pDriver->DeviceObject;IoDeleteDevice(pDev); // 调用IoDeleteDevice用于删除设备RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver"); // 初始化字符串将symLinkName定义成需要删除的符号链接名称IoDeleteSymbolicLink(&SymLinkName); // 调用IoDeleteSymbolicLink删除符号链接DbgPrint("驱动卸载完毕...");
}// 创建设备连接
NTSTATUS CreateDriverObject(IN PDRIVER_OBJECT pDriver)
{NTSTATUS Status;PDEVICE_OBJECT pDevObj;UNICODE_STRING DriverName;UNICODE_STRING SymLinkName;// 创建设备名称字符串RtlInitUnicodeString(&DriverName, L"\\Device\\LySharkDriver");Status = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);// 指定通信方式为缓冲区pDevObj->Flags |= DO_BUFFERED_IO;// 创建符号链接RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver");Status = IoCreateSymbolicLink(&SymLinkName, &DriverName);return STATUS_SUCCESS;
}// 创建回调函数
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{pIrp->IoStatus.Status = STATUS_SUCCESS; // 返回成功DbgPrint("派遣函数 IRP_MJ_CREATE 执行 \n");IoCompleteRequest(pIrp, IO_NO_INCREMENT); // 指示完成此IRPreturn STATUS_SUCCESS; // 返回成功
}// 关闭回调函数
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{pIrp->IoStatus.Status = STATUS_SUCCESS; // 返回成功DbgPrint("派遣函数 IRP_MJ_CLOSE 执行 \n");IoCompleteRequest(pIrp, IO_NO_INCREMENT); // 指示完成此IRPreturn STATUS_SUCCESS; // 返回成功
}// 主控制器,用于判断R3发送的控制信号
// lyshark.com
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;PIO_STACK_LOCATION pIrpStack;ULONG uIoControlCode;PVOID pIoBuffer;ULONG uInSize;ULONG uOutSize;// 获得IRP里的关键数据pIrpStack = IoGetCurrentIrpStackLocation(pIrp);// 获取控制码uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 输入和输出的缓冲区(DeviceIoControl的InBuffer和OutBuffer都是它)pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;// EXE发送传入数据的BUFFER长度(DeviceIoControl的nInBufferSize)uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// EXE接收传出数据的BUFFER长度(DeviceIoControl的nOutBufferSize)uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;// 对不同控制信号的处理流程switch (uIoControlCode){// 接收或发送case IOCTL_IO_LyShark:{DWORD dw = 0;// 得到输入参数memcpy(&dw, pIoBuffer, sizeof(DWORD));DbgPrint("[+] hello lyshark \n");// 对输入参数进行处理dw++;// 设置输出参数memcpy(pIoBuffer, &dw, sizeof(DWORD));// 返回通信状态status = STATUS_SUCCESS;break;}pIrp->IoStatus.Status = status;pIrp->IoStatus.Information = uOutSize;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return status;}// 设定DeviceIoControl的*lpBytesReturned的值(如果通信失败则返回0长度)if (status == STATUS_SUCCESS)pIrp->IoStatus.Information = uOutSize;elsepIrp->IoStatus.Information = 0;// 设定DeviceIoControl的返回值是成功还是失败pIrp->IoStatus.Status = status;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return status;
}// 入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{// 调用创建设备CreateDriverObject(pDriver);pDriver->DriverUnload = UnDriver; // 卸载函数pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; // 创建派遣函数pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; // 关闭派遣函数pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl; // 分发函数DbgPrint("By:LyShark ...");return STATUS_SUCCESS;
}
应用层通用测试模板代码如下:
#include <iostream>
#include <Windows.h>
#include <winioctl.h>#define IOCTL_IO_LyShark CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)int main(int argc, char *argv[])
{HANDLE hDevice = CreateFileA("\\\\.\\LySharkDriver", GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hDevice == INVALID_HANDLE_VALUE){CloseHandle(hDevice);return 0;}// 发送控制信号// input = 发送数据 output = 接受数据 ref_len = 数据长度DWORD input = 100, output = 0, ref_len = 0;DeviceIoControl(hDevice, IOCTL_IO_LyShark, &input, sizeof(input), &output, sizeof(output), &ref_len, 0);printf("输出: %d \n", output);system("pause");CloseHandle(hDevice);return 0;
}
输出效果如下: