5

我正在查看 WDK 中名为 minispy 的文件系统过滤器驱动程序示例......特别是它们如何使用 FilterSendMessage 和相关函数在用户空间和内核之间传递数据:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff541513%28v=vs.85%29.aspx

如果您安装 WDK,我正在查看并将参考的代码应位于此处:

WinDDK 根目录\version\src\filesys\miniFilter\minispy

所以基本上我首先要看的是 inc\minispy.h 中的共享头文件:

#pragma warning(push)
#pragma warning(disable:4200) // disable warnings for structures with zero length arrays.

typedef struct _LOG_RECORD {


ULONG Length;           // Length of log record.  This Does not include
ULONG SequenceNumber;   // space used by other members of RECORD_LIST

ULONG RecordType;       // The type of log record this is.
ULONG Reserved;         // For alignment on IA64

RECORD_DATA Data;
WCHAR Name[];           //  This is a null terminated string

} LOG_RECORD, *PLOG_RECORD;

这里我们的 Name 没有给出明确的大小,看起来他们正在使用一些选项来禁用警告。

现在我正在查看它的填写位置,filter\mspyLib.c:

(我只复制了我认为相关的行...)

VOID SpySetRecordName (__inout PLOG_RECORD LogRecord, __in PUNICODE_STRING Name)

    ULONG nameCopyLength;
    PCHAR copyPointer = (PCHAR)LogRecord->Name;
    ...
    // A bunch of code for getting nameCopyLength from UNICODE_STRING -- I understand this.
    ...

    // comment about adding sizeof(PVOID) for IA64 alignment -- I understand this.
    LogRecord->Length = ROUND_TO_SIZE( (LogRecord->Length + nameCopyLength + sizeof( UNICODE_NULL )), sizeof( PVOID ) );

    RtlCopyMemory( copyPointer, Name->Buffer, nameCopyLength );

    copyPointer += nameCopyLength;

    *((PWCHAR) copyPointer) = UNICODE_NULL;

所以我的问题基本上是这是在结构内部传递字符串以使用 FilterSendMessage 进行用户内核通信的最佳方法吗?我无法想象这些结构的布局以及如果名称字符串太大会发生什么。此外,结构的分配发生在其堆栈上的用户空间组件中,但调整大小发生在内核空间组件中,作用于传递的指向结构的指针。我认为这更多是我不了解零长度数组的问题,但是用户空间组件如何知道在调整名称之前为 Name 字段保留多少空间?

这本质上似乎是一种动态大小的数组形式,在几个线程中进行了讨论,例如:

C:动态大小结构的推荐样式

4

2 回答 2

-1

首先,是的,它似乎是一种动态大小的数组。基本上,Name字符串被放置在结构的末尾之后。在用户模式和内核模式之间传递数据时,它经常被使用。这种方法有几个优点:

  • 它不需要多次内存分配。
  • 当将数据从用户模式传递到内核模式(反之亦然)时,您通常需要将内存从一个缓冲区复制到另一个缓冲区(我相信 FilterSendMessage 会这样做)。如果我们使用指向不同内存位置的指针来存储字符串,我们将需要多次调用来复制(或锁定)内存。在处理用户提供的消息时,操作系统不可能知道数据结构的布局。解决这个问题的关键是使用上述的普通结构。

这是非常有用的方法。我个人使用这种技巧来避免多次调用内存函数(分配、复制、移动等),即使在简单的应用程序中也是如此。在开发 Windows 驱动程序时,我到处都能看到这样的结构(即 ZwQueryInformationFile、ZwQueryDirectoryFile 等)

于 2012-06-11T20:10:27.343 回答
-1

您需要先调用FilterConnectCommunicationPort () 以打开新连接,然后再调用FilterSendMessage ()。

于 2016-11-05T11:51:18.860 回答