用户态使用事件对象event与内核态交互

在用户态创建一个事件,得到句柄,传入到驱动中,驱动中发生某件事情时触发此事件。

下面代码中在用户创建一个事件句柄,将句柄值通过DeviceIoControl传入驱动中,在驱动中调用ObReferenceObjectByHandle回去句柄对象的指针,然后创建一个系统线程,触发此对象。

用户态返回后等待此事件对象是可以成功的,说明内核态中触发事件对象成功了。在内核态任意线程触发此事件指针都可以,记住不再使用事件对象时需要使用ObReferenceObjectByHandle递减驱动中的事件指针计数。

运行截图如下:

内核调试器打印如下:

 

 

 

 

 

 

 

用户态函数如下:

#define CTL_SYSSendEvent \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x850, METHOD_BUFFERED, FILE_WRITE_ACCESS)
int _tmain(int argc, _TCHAR* argv[])
{
  HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, L"");
  printf("hEvent:%x\n", hEvent);
  HANDLE hSys = CreateFile(L"\\\\.\\SysSetEvent", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
  printf("hSys:%x\n", hSys);
  DWORD dRetLength = 0;
  if (DeviceIoControl(hSys, CTL_SYSSendEvent, &hEvent, sizeof(HANDLE), NULL, 0, &dRetLength, 0))
  {
    printf("CTL_SYSSendEvent success");
    getchar();
    DWORD dWait = WaitForSingleObject(hEvent, INFINITE);
    if (WAIT_OBJECT_0 == dWait)
    {
      printf("WAIT_OBJECT_0 success");
    }
  }
  else
  printf("CTL_SYSSendEvent error:%d", GetLastError());
  getchar();
  return 0;
}

内核态代码如下:

#include <ntddk.h>

PDEVICE_OBJECT gloDevice = NULL;

#define CTL_SYSSendEvent \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x850, METHOD_BUFFERED, FILE_WRITE_ACCESS)

VOID threadProc(_In_ PVOID StartContext)
{
  PVOID object = StartContext;
  KeSetEvent(object, IO_NO_INCREMENT, FALSE);
  DbgPrint("threadProc ThreadId:%d irql:%d\r\n", PsGetCurrentThreadId(), KeGetCurrentIrql());
  ObDereferenceObject(object);
  object = NULL;
  PsTerminateSystemThread(STATUS_SUCCESS);
}
NTSTATUS driverDispatch(PDEVICE_OBJECT device, PIRP irp)
{
  NTSTATUS status = STATUS_SUCCESS;
  PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
  if (IRP_MJ_DEVICE_CONTROL == irpsp->MajorFunction)
  {
    PVOID buffer = irp->AssociatedIrp.SystemBuffer;
    ULONG inlen = irpsp->Parameters.DeviceIoControl.InputBufferLength;
    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
    {
    case CTL_SYSSendEvent:
    {
      DbgPrint("CTL_SYSSendEvent ThreadId:%d irql:%d\r\n", PsGetCurrentThreadId(), KeGetCurrentIrql());
      if (buffer == NULL || inlen != sizeof(HANDLE))
      {
        status = STATUS_INVALID_PARAMETER;
        break;
      }
      HANDLE hEvent = *(HANDLE*)buffer;
      PVOID object = NULL;
      status = ObReferenceObjectByHandle(hEvent, EVENT_MODIFY_STATE,
        *ExEventObjectType, UserMode, &object, NULL);

      if (NT_SUCCESS(status))
      {
        HANDLE thread = NULL;
        status = PsCreateSystemThread(&thread, 0, NULL, NULL, NULL, threadProc, object);
        if (NT_SUCCESS(status))
        {
          ZwClose(thread);
        }
        else
        {
          ObDereferenceObject(object);
          object = NULL;
        }
      }
      break;
    }
    default:
      break;
    }
  }
  irp->IoStatus.Information = 0;
  irp->IoStatus.Status = status;
  IoCompleteRequest(irp, IO_NO_INCREMENT);
  return status;
}

void DriverUnload(PDRIVER_OBJECT pDriver)
{
  UNREFERENCED_PARAMETER(pDriver);
  if (NULL != gloDevice)
  {
    IoDeleteDevice(gloDevice);
    gloDevice = NULL;
    UNICODE_STRING name_sym = RTL_CONSTANT_STRING(L"\\??\\SysSetEvent");
    IoDeleteSymbolicLink(&name_sym);
  }
  return;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegisterPath)
{
  NTSTATUS status = STATUS_SUCCESS;
  if (pDriver)
  {
    //创建一个设备
    UNICODE_STRING name_Device = RTL_CONSTANT_STRING(L"\\Device\\SysSetEvent");
    PDEVICE_OBJECT device = NULL;
    status = IoCreateDevice(pDriver, //创建的设备任意用户都可以打开 不安全
      0,
      &name_Device,
      FILE_DEVICE_UNKNOWN,
      FILE_DEVICE_SECURE_OPEN,
      FALSE,
      &gloDevice);

    UNICODE_STRING name_sym = RTL_CONSTANT_STRING(L"\\??\\SysSetEvent");
    IoCreateSymbolicLink(&name_sym, &name_Device);
    for (size_t i = 0; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
    {
      pDriver->MajorFunction[i] = driverDispatch;
    }
    pDriver->DriverUnload = DriverUnload;
  }
  return status;
}

posted @ 2022-11-10 15:45  psj00  阅读(231)  评论(0)    收藏  举报