0

I'm having an issue where I send a message to user-mode from kernel-mode using FltSendMessage that expects a reply. The struct being passed contains an int that is set to either 0 or 1. User-mode replies by setting this flag and calling FilterReplyMessage. However, when the message is received by the kernel, its value is always 56. No matter what number I set the flag to in user-mode, the kernel always receives the value 56. I'm confused as to where my error is.

I've tried changing the data type of passFlag from int to other types (USHORT etc..) which I knew probably wouldn't make a difference, but was worth a try.

Because the kernel message is replied to successfully (Checking user-mode HRESULT returns no errors and there is no timeout so if no reply is received the system would hang, which it does not), I know the error must be with the buffers being passed between user-mode and kernel-mode. I can't seem to find the reason why the passFlag is not being interpreted correctly in kernel-mode.

Can anyone help?

Shared Structure:

typedef struct _REPLY_MESSAGE_STRUCT {

    // Message header.
    FILTER_REPLY_HEADER header;

        // Flag to be set 
        // by user mode.
        int passFlag;

}REPLY_MESSAGE_STRUCT, *PREPLY_MESSAGE_STRUCT; 

Kernel Code:

DbgPrint("Sending Message...\n");

    replyBuffer.passFlag = 0;
    ULONG replySize = ((ULONG)sizeof(replyBuffer.header)) + ((ULONG)sizeof(replyBuffer));
    REPLY_MESSAGE_STRUCT replyBuffer;

    // Note: Try-catch statement has been omitted in this question to save time.
    // In the actual code there is a try-catch statement surrounding FltSendMessage.
    status = FltSendMessage(imageFilterData.filterHandle,
                    &imageFilterData.clientPort,
                    (PVOID)&sendingBuffer.messageBuffer,
                    sizeof(sendingBuffer.messageBuffer),
                    (PVOID)&replyBuffer,
                    &replySize,
                    0
                    );
    // Always returns 56
    // When a reply has been received.
    DbgPrint("Message received: %i\n", replyBuffer.passFlag);

User code:

// User-mode buffer is the same size as kernel-mode buffer.
ULONG replySize = ((ULONG)sizeof(replyBuffer.header)) + ((ULONG)sizeof(replyBuffer));
replyMessage.header.MessageId = messageFromKernel.header.MessageId;
REPLY_MESSAGE_STRUCT replyMessage;

// User-mode setting flag.
replyMessage.passFlag = 1;

// Flag is changed to 1 successfully.
printf("Test: %i\n", replyMessage.passFlag);

// Reply is sent successfully, but flag value on kernel end is always 56
hResult = FilterReplyMessage(port,
    &replyMessage.header,
    replySize);

_com_error err2(hResult);

errorMessage = err2.ErrorMessage();

// No errors.
printf("Result: %s\n", errorMessage);

What I have tried:

  • Changing the datatype of passFlag.

  • Going through every step before and after FltSendMessage and FilterReply message to find if the value is being changed before being sent back to the kernel.

  • Unrelated to your question and problem, but symbols starting with an underscore and followed by an upper-case letter (like `_REPLY_MESSAGE_STRUCT`) are reserved in all scopes. See e.g. [this old answer](https://stackoverflow.com/a/228797/440558) for more details. – Some programmer dude May 15 '18 at 09:33
  • Also, please don't use multiple language tags unless it's actually relevant and you're working with multiple languages or asking about differences between multiple languages. If you program in C then use only the C tag. – Some programmer dude May 15 '18 at 09:35
  • Thanks for your reply, but just so you know user-mode is in C++ and kernel-mode is in C. Hence the need for C++ and C tags. As I dont know where the error could be, either in user-mode application or kernel-mode filter but, thank-you for your suggestion. – user6719374 May 15 '18 at 09:42
  • `FILTER_REPLY_HEADER` is only for user mode `FilterReplyMessage` and `FilterGetMessage`. the kernel mode buffer must not begin from `FILTER_REPLY_HEADER` - you invalid use buffer in kernel mode. remove `FILTER_REPLY_HEADER header;` from kernel mode definition – RbMm May 15 '18 at 09:52
  • @Someprogrammerdude - may be this is surprise, but windows headers itself permanent use this notation. for example [`_FILTER_REPLY_HEADER`](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/fltuserstructures/ns-fltuserstructures-_filter_reply_header) – RbMm May 15 '18 at 09:53
  • @RbMm Thanks for your suggestion! Removing the reply stuct from the kernel mode definition stops the kernel mode from recieving the reply. This could be due to the difference in the structs being passed between user-mode and kernel-mode. – user6719374 May 15 '18 at 10:11
  • look for example [scanner](https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/miniFilter/scanner/user/scanuser.h) - how here structures defined – RbMm May 15 '18 at 10:14
  • `FILTER_REPLY_HEADER` and `FILTER_MESSAGE_HEADER` used only by user mode. not by kernel. you must define self separate structures for message and reply. and kernel mode use it direct, user mode - use another structs - inherit from `FILTER_MESSAGE_HEADER` (or `FILTER_REPLY_HEADER`) and custom structs – RbMm May 15 '18 at 10:18

1 Answers1

0

you are using error data in call FltSendMessage:

ReplyBuffer is pointer to custom user defined data. it must not begin from FILTER_REPLY_HEADER SenderBuffer is pointer to custom user defined data. it must not begin from FILTER_MESSAGE_HEADER

first of all you need define structures, that are shared between kernel and user mode, for message and reply. for example

struct SCANNER_NOTIFICATION {
    // any custom data
    int someData;

};

struct SCANNER_REPLY {
    // any custom data
    int passFlag;
};

and in kernel mode you direct use it as is:

SCANNER_NOTIFICATION send;
SCANNER_REPLY reply;
ULONG ReplyLength = sizeof(reply);

FltSendMessage(*, *, &send, sizeof(send), &reply, &ReplyLength, *);

in user mode you need define 2 additional structures:

struct SCANNER_MESSAGE : public FILTER_MESSAGE_HEADER, public SCANNER_NOTIFICATION {};

struct SCANNER_REPLY_MESSAGE : public FILTER_REPLY_HEADER, public SCANNER_REPLY {};

(i use c++ style here, when here used c style) and in user mode we need use next, for example:

SCANNER_MESSAGE* mesage;
FilterGetMessage(*, mesage, sizeof(SCANNER_MESSAGE), *);

and

    SCANNER_REPLY_MESSAGE reply;
    reply.MessageId = mesage->MessageId;
    FilterReplyMessage(*, &reply, sizeof(reply));
RbMm
  • 31,280
  • 3
  • 35
  • 56