【问题标题】:WDM driver and user-mode communication: best practices and callback questionsWDM 驱动程序和用户模式通信:最佳实践和回调问题
【发布时间】:2018-07-12 04:48:08
【问题描述】:

我的驱动程序的目的是通知用户模式应用程序我收到的每个回调,并将我从那些注册例程获得的数据传递给它。然后,用户模式应用程序将在屏幕上打印它从内核接收到的所有信息(它是一个简单的 Win32 控制台应用程序)。我目前注册了三个回调:PsSetCreateProcessNotifyRoutineExPsSetCreateProcessNotifyRoutineEx2PsSetLoadImageNotifyRoutine。我想知道:

1) 考虑到许多进程和许多图像可以在同一时间?

2) 我应该为每次调用实现这样的方法,还是应该存储一些信息并每隔 0.5 秒将它们推送到用户模式?
我实际上使用下面的代码在驱动中定义IOCTL:

#define IOCTL_RECEIVE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA)

这是我的 DispatchDeviceControl 函数的代码:

NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    KIRQL CurrentIRQL = KeGetCurrentIrql();
    DbgPrint("DispatchDeviceControl called at IRQL level: %d", CurrentIRQL);

    PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
    NTSTATUS status = STATUS_SUCCESS;
    PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
    ULONG inLength = irpsp->Parameters.DeviceIoControl.InputBufferLength;
    ULONG outLength = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
    ULONG returnLength = 0;
    pMsg PMSG = NULL;

    switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
    {   
    case IOCTL_RECEIVE:
        DbgPrint("IOCTL_RECEIVE message sent\n");
        KeWaitForSingleObject(&kEvent, Executive, KernelMode, 0, NULL);
        PMSG = (pMsg)ExInterlockedRemoveHeadList(&listhead, &spinlock);
        // Copy data to the buffer
        RtlCopyMemory((PCHAR)buffer, (PCHAR)PMSG, sizeof(Msg));
        // Release the structure
        ExFreePool(PMSG);
        // Set returnLength
        returnLength = sizeof(Msg);
        break;
    default:
        status = STATUS_INVALID_PARAMETER;
    }
    Irp->IoStatus.Status = status;
    Irp->IoStatus.Information = returnLength;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return status;
}

还有我的一个回调例程的代码:

_Use_decl_annotations_
VOID prcmPsCreateProcessNotifyRoutineEx2(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo)
{
    // If process is exiting, just return immediately
    if (CreateInfo == NULL)
        return;

    pMsg PMSG = (pMsg)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(Msg), 'prcm');

    if (PMSG == NULL)
    {
        DbgPrint("PsCreateProcessNotifyRoutineEx2: ERROR allocating Pool space for data to be sent to user mode\n");
        return;
    }

    // Fill data
    PMSG->ParentId = NULL;
    PMSG->ProcessId = ProcessId;
    PMSG->FullImageName = NULL;

    ExInterlockedInsertHeadList(&listhead, (PLIST_ENTRY)PMSG, &spinlock);
    KeSetEvent(&kEvent, 0, FALSE);

    return;
}

最后是结构定义(我包含了一些示例值,但第一个元素显然是LIST_ENTRY

typedef struct {
    LIST_ENTRY listhead;
    HANDLE ParentId;
    HANDLE ProcessId;
    PUNICODE_STRING FullImageName;
} Msg, *pMsg;

供您参考,我正确调用了我的DriverEntry 函数:

KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
KeInitializeSpinLock(&spinlock);
InitializeListHead(&listhead);

在我的用户模式控制台应用程序中,我在主例程中创建了一个线程,并在其相关线程函数中不断检查DeviceIoControl 的返回值,以便实时打印我从

3) 有点跑题了,但我认为这是相关的:我在用户模式下错过一些通知是否正常,使用此代码?有人知道为什么吗?

【问题讨论】:

    标签: c windows kernel drivers wdm


    【解决方案1】:

    OSR 写了一篇很棒的文章,The Inverted Call Model。这种系统的基本设计包括服务、驱动程序和两者之间的一些协议。它适用于单片驱动程序以及分层驱动程序,并且只要求驱动程序能够接收设备控制操作。

    我还想提一下,您同时使用了 PsSetCreateProcessNotifyRoutineEx 和 PsSetCreateProcessNotifyRoutineEx2。您应该使用其中一种。从 Windows 10, version 1703 Windows Server 2016 开始支持 PsSetCreateProcessNotifyRoutineEx2。它提供了更好的功能,所以我建议尽可能使用它。

    您可以通过使用MmGetSystemRoutinAddress 来确定使用哪个来动态使用 PsSetCreateProcessNotifyRoutineEx2,如果它不可用,则使用 PsSetCreateProcessNotifyRoutineEx。

    【讨论】:

    • 我不知道这种方法,据我所知,这是实现我的目标的最佳方式。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2010-11-09
    • 2016-07-14
    • 2019-04-04
    • 1970-01-01
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多