内核中执行代码后需要将结果动态显示给应用层的用户,DeviceIoControl
是直接发送控制代码到指定的设备驱动程序,使相应的移动设备以执行相应的操作的函数,如下代码是一个经典的驱动开发模板框架,在开发经典驱动时会用到的一个通用案例。
如下这段案例中,我们只介绍DispatchIoctl
,该函数主要用于接收或发送IOCTL
控制信号,以此来实现接收和发送数据。
首先,通过调用IoGetCurrentIrpStackLocation
函数获取IRP(I/O Request Packet)
的堆栈位置,并获取控制码、输入和输出缓冲区的相关信息。
然后,根据不同的控制信号码,进行相应的处理流程。这里的示例代码只列出了一个控制信号码(IOCTL_IO_LyShark)
的处理流程,即接收传入数据,进行处理后返回传出数据。
最后,根据处理结果,设置IRP
的状态和返回信息,并通过调用IoCompleteRequest
函数完成IRP
的处理。
需要注意的是,这段代码中没有对错误情况进行处理,如果出现错误,返回的状态码为STATUS_INVALID_DEVICE_REQUEST
。因此,实际使用中需要根据具体情况进行修改和完善。
驱动程序开发通用模板代码如下:
#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; pDev = pDriver->DeviceObject; IoDeleteDevice(pDev); RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver"); IoDeleteSymbolicLink(&SymLinkName); 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); return STATUS_SUCCESS; }
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; DbgPrint("派遣函数 IRP_MJ_CLOSE 执行 \n"); IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; }
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;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
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; }
if (status == STATUS_SUCCESS) pIrp->IoStatus.Information = uOutSize; else pIrp->IoStatus.Information = 0;
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; }
|
而在应用层中,最需要注意的是函数DeviceIoControl
它是Windows API
中的一个系统函数其工作于应用层,用于与设备驱动程序通信。该函数可以向设备驱动程序发送控制码,同时传输输入和输出缓冲区的数据。以下是该函数的语法:
BOOL DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped );
|
参数解释:
- hDevice:要访问的设备的句柄,可以使用CreateFile函数获得。
- dwIoControlCode:设备驱动程序定义的控制码。
- lpInBuffer:输入缓冲区的指针,用于向设备驱动程序传递输入数据。
- nInBufferSize:输入缓冲区的大小(以字节为单位)。
- lpOutBuffer:输出缓冲区的指针,用于从设备驱动程序获取输出数据。
- nOutBufferSize:输出缓冲区的大小(以字节为单位)。
- lpBytesReturned:返回的字节数指针,用于记录成功传输的字节数。
- lpOverlapped:用于异步I/O操作的指针。
在驱动程序中,要实现DeviceIoControl
函数的处理,需要在IRP的IoControlCode
中获取控制码,并在AssociatedIrp.SystemBuffer
中获取输入数据,将处理结果放回到同一个SystemBuffer
中,然后将SystemBuffer
中的数据作为输出数据传回给用户层。具体处理过程可以参考示例代码中的DispatchIoctl
函数。
总的来说,DeviceIoControl
函数提供了一种方便的方法,可以让用户层应用程序与设备驱动程序进行通信,实现设备的控制、配置和数据传输等功能。
应用层通用测试模板代码如下:
#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; }
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; }
|
输出效果如下: