简体   繁体   English

Windows驱动程序 - 在用户模式和内核模式之间传递字符串。 动态大小的结构

[英]Windows Driver - Passing strings between user mode and kernel mode. Dynamically sized struct

I am looking at the File System Filter driver example in the WDK called minispy... specially how they are passing data between userspace and the kernel using the FilterSendMessage and related functions: 我正在查看WDK中名为minispy的文件系统过滤器驱动程序示例...特别是它们如何使用FilterSendMessage和相关函数在用户空间和内核之间传递数据:

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

The code I am looking at and will be referring to should be located here if you install the WDK: 如果您安装WDK,我正在查看并将引用的代码应位于此处:

WinDDK Root Dir\\version\\src\\filesys\\miniFilter\\minispy WinDDK Root Dir \\ version \\ src \\ filesys \\ miniFilter \\ minispy

So basically the first thing I am looking at is the shared header file in inc\\minispy.h: 所以我首先要看的是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;

Here we have Name which is not given an explicit size and it looks like they are using some options to disable warnings for this. 这里我们有Name没有明确的大小,看起来他们正在使用一些选项来禁用此警告。

Now I am looking at where this is filled in, filter\\mspyLib.c: 现在我正在查看填充的位置,filter \\ mspyLib.c:

(I only copied lines I thought were relevant...) (我只复制了我认为相关的行......)

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;

So my question is basically is this the best method for passing strings inside of a struct for user-kernel communication using FilterSendMessage? 所以我的问题基本上是使用FilterSendMessage在结构中传递字符串以进行用户内核通信的最佳方法吗? I'm having trouble picturing the layout of these structs and what happens if the name string turns out to be too big. 我无法想象这些结构的布局,如果名称字符串太大,会发生什么。 Also, allocation for the struct happens in the userspace component on it's stack but the resize happens in kernel space component acting on a passed pointer to the struct. 此外,struct的分配发生在它的堆栈上的userspace组件中,但resize发生在内核空间组件中,作用于传递给struct的指针。 I think this is more a problem of me not understanding zero length arrays but how does the userspace component know how much space to reserve for the Name field before its resized? 我认为这不是我不理解零长度数组的问题,而是用户空间组件如何知道在调整大小之前为Name字段保留多少空间?

This essentially seems to be a form of dynamically sized arrays which is discussed in several threads such as: 这基本上似乎是动态大小的数组的形式,在几个线程中讨论,例如:

C: Recommended style for dynamically sized structs C:动态大小结构的推荐样式

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

First of all, yes, it appears to be a form of dynamically sized array. 首先,是的,它似乎是一种动态大小的数组。 Basically, the Name string is placed right after the end of structure. 基本上, Name字符串放在结构的结尾之后。 When passing data between user- and kernel-mode it is very often used trick. 在用户模式和内核模式之间传递数据时,经常使用技巧。 There are several advantages of this approach: 这种方法有几个优点:

  • It does not require several memory allocations. 它不需要多次内存分配。
  • When passing data from user mode to kernel mode (and vice versa) you often need to copy memory from one buffer to another (I believe FilterSendMessage does that). 将数据从用户模式传递到内核模式(反之亦然)时,您经常需要将内存从一个缓冲区复制到另一个缓冲区(我相信FilterSendMessage会这样做)。 If we use pointer to a different memory location for storing string we will need several calls to copy (or lock) memory. 如果我们使用指向不同内存位置的指针来存储字符串,我们将需要多次调用来复制(或锁定)内存。 When dealing with user-supplied messages it is impossible to OS to know the layout of your data structure. 处理用户提供的消息时,操作系统无法知道数据结构的布局。 The key to solving this problem is to use plain structure as the one described above. 解决这个问题的关键是使用如上所述的平面结构。

It is very useful approach. 这是非常有用的方法。 I personally use such trick to avoid multiples calls to memory functions (allocate, copy, move etc.) even in simple applications. 我个人使用这样的技巧来避免即使在简单的应用程序中多次调用内存函数(分配,复制,移动等)。 When developing Windows drivers I see such structures everywhere (ie ZwQueryInformationFile, ZwQueryDirectoryFile etc.) 在开发Windows驱动程序时,我到处都看到这样的结构(即ZwQueryInformationFile,ZwQueryDirectoryFile等)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM