Click here to Skip to main content
15,889,216 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hey,

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 and 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.

Thank-you to anyone who takes the time to review my question.
Cheers!

Shared Structure:
C++
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:
C++
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:

C++
// 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.
Posted
Updated 15-May-18 0:02am

1 solution

The posted code makes no sense and should not even compile because you are using REPLY_MESSAGE_STRUCT variables before they have been declared at both sides.

The size calculation is also wrong because you are adding the size of the whole reply structure instead that of the components:
ULONG replySize = ((ULONG)sizeof(replyBuffer.header)) + ((ULONG)sizeof(replyBuffer));
It must be
ULONG replySize = sizeof(replyBuffer.header) + sizeof(replyBuffer.passFlag);
or
ULONG replySize = sizeof(FILTER_REPLY_HEADER) + sizeof(int);

You should also always initialise all required fields of structures:
// This is missing in your code.
// When not clearing Status here it may contain any random value.
replyMessage.header.Status = 0; 
// Set other members
replyMessage.header.MessageId = messageFromKernel.header.MessageId;
replyMessage.passFlag = 1;

This might still not solve your problem but will avoid at least other problems that arise later.

I have not used such filters so far. So I can't help more. But you should read the Microsoft documentation about these filters and the used functions. It might be also helpful for searching the web for example code to see how other's have it done.
 
Share this answer
 
Comments
Member 13809184 15-May-18 6:04am    
Thanks Jochen,

It's my bad, I've left a decent amount of code out to save space. All values are instantiated before being used (Including struct values). Forgive me for not laying out the code correctly there is a decent amount that I left out. I just tried to get the important stuff to save the readers time.

Everything builds and runs correctly. Including a successful message being sent to user-mode from kernel-mode and the reply to kernel-mode from user-mode works as well. The only issue is the passFlag value doesn't change.

Sadly according to Microsoft documentation there can be some padding issues so they recommending calculating the size of the buffer by adding the size of replyStruct.header + replyStruct
Reference:
(https://msdn.microsoft.com/en-us/library/windows/hardware/ff541508(v=vs.85).aspx)

Thanks again for your reply Jochen!
Jochen Arndt 15-May-18 6:13am    
I have read the documentation about the padding like you. But you have added sizeof(replyStruct) (the total struct size) instead of sizeof(mystruct) (the size of the additional data; int in your case)!

Regarding the Status member:
When having a debug build that will be initialised to NULL. But once you make a release build the structure memory will not be cleared upon declaration!

Regarding the not seen data value:
What is the flow of the functions (in which order are they called and are they overlapped or not)?

Again: It might help to check sources in the web that used such filters.
Member 13809184 15-May-18 6:44am    
Thanks Jochen,

I've changed the values accordingly.

Size calculation is = ULONG replySize = ((ULONG)sizeof(replyBuffer.header)) + ((ULONG)sizeof(replyBuffer));

Status is also set in user mode:

replyMessage.header.Status = 0;

The value in kernel mode now is always 40.

As for flow of functions, During driver entry I instantiate my structures and register my communication port(imageFilterData.filterHandle and imageFilterData.clientPort). I'm registered to listen for MJ_CREATE. During PostOperation I get the filename safely , parse it and copy it into sendingBuffer.messageBuffer (message struct definition below). Then I send it off to user-mode with an allocated reply buffer using FltSendMessage. User-mode receives the file-name successfully. Does some basic processing using the filename then returns 0 or 1 to the filter using FltReplyMessage. Then I attempt to see what value is returned to the kernel and I get some constant unrelated value. If user-mode sends the pass flag 0, kernel mode gets 40 or 56. If user-mode sends 1, kernel-mode gets 40 or 56. I know I must be doing something wrong with the buffer.

Sender Message Struct:
This is passed to user-mode. Filename is copied to message buffer.
typedef struct _MESSAGE_STRUCT {

FILTER_MESSAGE_HEADER header;

PVOID messageBuffer[400];

}MESSAGE_STRUCT , *PMESSAGE_STRUCT;


I've read the WDK minispy and scanner samples regarding user communication. I can't seem to catch what I'm missing. But I will continue, I know there is something I'm missing.

Thanks again for taking the time to take a look at my problem!
Jochen Arndt 15-May-18 7:24am    
That is a buffer of 400 pointers:
PVOID messageBuffer[400];

However, you are probably using the wrong buffer at some step. The buffer used by FilterReplyMessage() is not the same buffer as those used at the kernel side when calling FltSendMessage(). So that is never changed (BTW: codes 40 and 56 are the characters '(' and '8').

As already noted I have never used such filters. But it seems that you have to use the buffer passed by FltSendMessage() when replying or get access to the passed buffer in the kernel side (if there is some function to get it).
Member 13809184 17-May-18 3:38am    
Hey Jochen, thanks so much for your input. I found my issue it was with my structs. Thanks so much again.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900