TimeOut

Hi.

I have the following code;
KeQuerySystemTime(&CurrentTime);
DbgPrint(“>%d.\n”, CurrentTime.QuadPart);
KeQuerySystemTime(&TimeOut);
DbgPrint(“>>%d.\n”, TimeOut.QuadPart);
TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG) 10*1000*1000);
while(CurrentTime.QuadPart <= TimeOut.QuadPart)
{
KeQuerySystemTime(&CurrentTime);
}

The Problem is CurrentTime seems to be negative and TimeOut positive. When printing (before TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG) 10*1000*1000):wink: TimeOut seems to be about 10,000,000 out from CurrentTime. Am I doing something I can’t see here?

Thanks.

I am not sure what you are really trying to so but your DbgPrint statements
are wrong. You are using a %d to output an int64.
If you want a delay why don’t you use KeDelayExecutionThread?

Bill Wandel

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]
On Behalf Of xxxxx@hotmail.co.uk
Sent: Sunday, December 06, 2009 2:45 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] TimeOut

Hi.

I have the following code;
KeQuerySystemTime(&CurrentTime);
DbgPrint(“>%d.\n”, CurrentTime.QuadPart); KeQuerySystemTime(&TimeOut);
DbgPrint(“>>%d.\n”, TimeOut.QuadPart); TimeOut.QuadPart =
CurrentTime.QuadPart + ((LONGLONG) 10*1000*1000); while(CurrentTime.QuadPart
<= TimeOut.QuadPart) { KeQuerySystemTime(&CurrentTime); }

The Problem is CurrentTime seems to be negative and TimeOut positive. When
printing (before TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG)
10*1000*1000):wink: TimeOut seems to be about 10,000,000 out from CurrentTime.
Am I doing something I can’t see here?

Thanks.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Other than the issue Bill mentioned about the debug prints being incorrect
and that you should use an OS provided call for spinning delays, have you
stepped through the code in assembly mode? Have you inspected the output
.cod listing from this function and decode how each contributes to producing
your desired results?

The above is influenced by my strong belief that no one should be working in
the kernel without knowing assembly. At least the x86 (i386) form and have
the motivation and skills to also work with x64 and ia64 assembly when
required. It is possible to write code in x86 that will fail under x64, but
it takes wearing really big blinders to do so.

wrote in message news:xxxxx@ntdev…
> Hi.
>
> I have the following code;
> KeQuerySystemTime(&CurrentTime);
> DbgPrint(“>%d.\n”, CurrentTime.QuadPart);
> KeQuerySystemTime(&TimeOut);
> DbgPrint(“>>%d.\n”, TimeOut.QuadPart);
> TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG) 1010001000);
> while(CurrentTime.QuadPart <= TimeOut.QuadPart)
> {
> KeQuerySystemTime(&CurrentTime);
> }
>
> The Problem is CurrentTime seems to be negative and TimeOut positive. When
> printing (before TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG)
> 1010001000):wink: TimeOut seems to be about 10,000,000 out from CurrentTime.
> Am I doing something I can’t see here?
>
> Thanks.
>

I could program in assembly.

Is there a way of breaking the loop should I set for example X=1 in another thread and function?

What would using assembly accomplish?
If you want a timeout that can be broken you can always use an event with a
timeout.

Bill Wandel

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]
On Behalf Of xxxxx@hotmail.co.uk
Sent: Monday, December 07, 2009 11:21 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] TimeOut

I could program in assembly.

Is there a way of breaking the loop should I set for example X=1 in another
thread and function?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

I mean I could program in assembly if I wanted. I was commenting on David J. Craig comments that anyone wishing to develop Drivers should at least be able to write in assembly. I sometimes forget that most users of osronline use e-mail.

Thankyou, I have placed in a loop for the meantime. I will look into it.


RE: TimeOut


What would using assembly accomplish?
If you want a timeout that can be broken you can always use an event with a
timeout.

Bill Wandel

You should be using KeStallExecutionProcessor, KeDelayExecutionThread,
or wait on an event with a timeout using KeWaitForSingleObject. What
you should not be doing is going off and inventing your own buggy
delay loops.

Mark Roddy

On Mon, Dec 7, 2009 at 11:20 AM, wrote:
> I could program in assembly.
>
> Is there a way of breaking the loop should I set for example X=1 in another thread and function?
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
>

xxxxx@hotmail.co.uk wrote:

I have the following code;
KeQuerySystemTime(&CurrentTime);
DbgPrint(“>%d.\n”, CurrentTime.QuadPart);
KeQuerySystemTime(&TimeOut);
DbgPrint(“>>%d.\n”, TimeOut.QuadPart);
TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG) 10*1000*1000);
while(CurrentTime.QuadPart <= TimeOut.QuadPart)
{
KeQuerySystemTime(&CurrentTime);
}

The Problem is CurrentTime seems to be negative and TimeOut positive. When printing (before TimeOut.QuadPart = CurrentTime.QuadPart + ((LONGLONG) 10*1000*1000):wink: TimeOut seems to be about 10,000,000 out from CurrentTime. Am I doing something I can’t see here?

I’m not sure yet that you understand what you are doing wrong here.
You’re printing a 64-bit value (QuadPart) using a 32-bit descriptor
(%d). The results are certainly going to be unexpected. Change the
“%d” to %I64d" to print all 64 bits.

However, if you actually release a driver where you spin in a tight CPU
loop for 1 full second, people will hunt you down and beat you up.
Further, if you should happen to do this at a raised IRQL, your machine
will lock up permanently. KeQuerySystemTime is updated during timer
interrupts. If the timer interrupt can’t run, the time will never be
updated. If you want to delay, use KeDelayExecutionThread.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

The loop function was simply.
for(i=0 to 10) { KeDelayExecutionThread(); if check == TRUE; break }

As temporary to break the timeout a little while I tested something.

The problem I have is, I am receiving messages via a user application. If the message comes in it is changing a global DWORD variable which I want another function to pick up on the moment the change occurs.

xxxxx@hotmail.co.uk wrote:

The loop function was simply.
for(i=0 to 10) { KeDelayExecutionThread(); if check == TRUE; break }

As temporary to break the timeout a little while I tested something.

The problem I have is, I am receiving messages via a user application. If the message comes in it is changing a global DWORD variable which I want another function to pick up on the moment the change occurs.

I can’t imagine what problem you are trying to solve here. If you need
to have one user-mode request wait on another user-mode request, then
you should be using something like an event rather than a polled loop.
Any time you find yourself using a polled loop like this, it is almost
always a bad design decision.

I know this is just pseudo-code, but remember in this case that the
variable “check” must be declared “volatile”. Otherwise, the compiler
is allowed to assume that the variable will not change in the middle of
the loop, so it might move the test outside the loop.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

The solution is to solve the problem of the minifilter scanner example of when attempting to break into the application for debugging. Overal the solution works but other than using KeDelayExecutionThread in this way and it is used in the filter (although it probably shouldn't be, I am limiting the number of threads.) it is the best solution I have and can come up with.

I.e. Driver sends a message to the user application, and awaits a responce, if there is a timeout, the driver checks to see what the user application has sent. If the user application has sent a message asking for additional time the driver waits a little longer. This is so information can be sent to the end user to manually make certain choices affecting what can and cannot be loaded.

Does that make sense?

N.

xxxxx@hotmail.co.uk wrote:

The loop function was simply.
for(i=0 to 10) { KeDelayExecutionThread(); if check == TRUE; break }

As temporary to break the timeout a little while I tested something.

The problem I have is, I am receiving messages via a user application. If the
message comes in it is changing a global DWORD variable which I want another
function to pick up on the moment the change occurs.

I can't imagine what problem you are trying to solve here. If you need
to have one user-mode request wait on another user-mode request, then
you should be using something like an event rather than a polled loop.
Any time you find yourself using a polled loop like this, it is almost
always a bad design decision.

I know this is just pseudo-code, but remember in this case that the
variable "check" must be declared "volatile". Otherwise, the compiler
is allowed to assume that the variable will not change in the middle of
the loop, so it might move the test outside the loop.

--
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

The problem makes sense, your solution not so much.

Having dealt with this issue, a simpler solution is to make the
timeout runtime configurable so that when you are debugging your
service application you can set the timeout to effectively forever so
that the message timeout doesn’t get in the way of your application
debugging.

Mark Roddy

On Tue, Dec 8, 2009 at 1:47 PM, wrote:
> The solution is to solve the problem of the minifilter scanner example of when attempting to break into the application for debugging. Overal the solution works but other than using KeDelayExecutionThread in this way and it is used in the filter (although it probably shouldn’t be, I am limiting the number of threads.) it is the best solution I have and can come up with.
>
> I.e. Driver sends a message to the user application, and awaits a responce, if there is a timeout, the driver checks to see what the user application has sent. If the user application has sent a message asking for additional time the driver waits a little longer. This is so information can be sent to the end user to manually make certain choices affecting what can and cannot be loaded.
>
> Does that make sense?
>
> N.
> –
> xxxxx@hotmail.co.uk wrote:
>> The loop function was simply.
>> for(i=0 to 10) { KeDelayExecutionThread(); if check == TRUE; break }
>>
>> As temporary to break the timeout a little while I tested something.
>>
>> The problem I have is, I am receiving messages via a user application. If the
> message comes in it is changing a global DWORD variable which I want another
> function to pick up on the moment the change occurs.
>>
>
> I can’t imagine what problem you are trying to solve here. ?If you need
> to have one user-mode request wait on another user-mode request, then
> you should be using something like an event rather than a polled loop.
> Any time you find yourself using a polled loop like this, it is almost
> always a bad design decision.
>
> I know this is just pseudo-code, but remember in this case that the
> variable “check” must be declared “volatile”. ?Otherwise, the compiler
> is allowed to assume that the variable will not change in the middle of
> the loop, so it might move the test outside the loop.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
>

> I.e. Driver sends a message to the user application, and awaits a responce, if there is a timeout

I would disable the timeout feature if the app is being debugged.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Tim Roberts wrote:

Further, if you should happen to do this at a raised IRQL, your
machine will lock up permanently.

Anton, I’m disappointed – where’s your complaint about so-and-so CDROM driver (or whatever) that can hang the machine for several seconds, even though it’s WHQLed…

Tish tish Chris:

“Bear Baiting” is the last thing we need here…

Cheers,
Dave

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Tuesday, December 08, 2009 5:58 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] TimeOut

Tim Roberts wrote:

Further, if you should happen to do this at a raised IRQL, your
machine will lock up permanently.

Anton, I’m disappointed – where’s your complaint about so-and-so CDROM
driver (or whatever) that can hang the machine for several seconds, even
though it’s WHQLed…


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

The problem is, if I break into the user application while there is an infinite loop routine present the application freezes Windows. This is because the driver hasn’t detected it has been disconnected (because it technically hasn’t.) and so it passes any file that is being used to the user application which at the present moment in time unable to send a reply to stop the inifinite loop. (That is what happens when I use a debugger on the user application.)

The first solution I tried was sending a temporary packet to the user application and if it replied then I would send the infinite FltSendMessage. This worked partly but not on everything. I had some freeze problems which I was unable to solve.

So my third solution was to try this way. (My forth will probably be a ping pong style communication.) periodically the user application sends the driver a message to say that it is still working. If it doesn’t, the driver uses default settings. In other words the method I described in my previous post.

I hope it makes sense. This way there is no freeze and no require for reboots and I can safely debug the application. If there is a better way please let me know.

N.


The problem makes sense, your solution not so much.

Having dealt with this issue, a simpler solution is to make the
timeout runtime configurable so that when you are debugging your
service application you can set the timeout to effectively forever so
that the message timeout doesn’t get in the way of your application
debugging.

Mark Roddy

On Tue, Dec 8, 2009 at 1:47 PM, wrote:
> The solution is to solve the problem of the minifilter scanner example of when
attempting to break into the application for debugging. Overal the solution
works but other than using KeDelayExecutionThread in this way and it is used in
the filter (although it probably shouldn’t be, I am limiting the number of
threads.) it is the best solution I have and can come up with.
>
> I.e. Driver sends a message to the user application, and awaits a responce, if
there is a timeout, the driver checks to see what the user application has sent.
If the user application has sent a message asking for additional time the driver
waits a little longer. This is so information can be sent to the end user to
manually make certain choices affecting what can and cannot be loaded.
>
> Does that make sense?
>
> N.
> –
> xxxxx@hotmail.co.uk wrote:
>> The loop function was simply.
<…excess quoted lines suppressed…>

xxxxx@hotmail.co.uk wrote:

The problem is, if I break into the user application while there is an infinite loop routine present the application freezes Windows. This is because the driver hasn’t detected it has been disconnected (because it technically hasn’t.) and so it passes any file that is being used to the user application which at the present moment in time unable to send a reply to stop the inifinite loop. (That is what happens when I use a debugger on the user application.)

And this is exactly why it is such an extremely bad idea to loop in a
driver. Use events and pending requests instead. That’s why they were
invented.

Here’s a “mental model” that works for me. Your driver should always
behave as though it is borrowing someone else’s thread (because, that’s
essentially what it does). Because of that, it has to be a “good
neighbor” about borrowing. It can’t steal the thread forever, it can’t
waste time doing nothing, making the thread useless. You need to do as
much as you can actively do, then mark the request pending, queue it,
and return so the thread can do other things. Later, when you get some
signal that lets you finish the job, you are borrowing some OTHER thread.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Can you give me some pointers and guides?

Effectively I need to know the file will not be opened until an ok is given.


xxxxx@hotmail.co.uk wrote:

The problem is, if I break into the user application while there is an
infinite loop routine present the application freezes Windows. This is because
the driver hasn’t detected it has been disconnected (because it technically
hasn’t.) and so it passes any file that is being used to the user application
which at the present moment in time unable to send a reply to stop the inifinite
loop. (That is what happens when I use a debugger on the user application.)

And this is exactly why it is such an extremely bad idea to loop in a
driver. Use events and pending requests instead. That’s why they were
invented.

Here’s a “mental model” that works for me. Your driver should always
behave as though it is borrowing someone else’s thread (because, that’s
essentially what it does). Because of that, it has to be a “good
neighbor” about borrowing. It can’t steal the thread forever, it can’t
waste time doing nothing, making the thread useless. You need to do as
much as you can actively do, then mark the request pending, queue it,
and return so the thread can do other things. Later, when you get some
signal that lets you finish the job, you are borrowing some OTHER thread.

xxxxx@hotmail.co.uk wrote:

Can you give me some pointers and guides?

Effectively I need to know the file will not be opened until an ok is given.

Several people, including myself, have already given you pointers and
guides. Even though I’ve never done a file-system driver, it only took
me a few minutes with Google to find this:
http://msdn.microsoft.com/en-us/library/ms793705.aspx
Just save the CallbackData pointer in a context somewhere, and return
FLT_POSTOP_MORE_PROCESSING_REQUIRED. Then, when you get the approval,
you call FltCompletePendedPostOperation to continue the processing. You
probably don’t need the work item in your scenario.

How are you communicating with the approval app?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

FltSendMessage.

Below is the code I had been using before I began reading into workitems.

#include <fltkernel.h>
#include <dontuse.h>
#include <suppress.h>
#include <ntddk.h>
#include <ntifs.h>

#pragma warning(disable:4995)
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>
#pragma warning(default:4995)

const PWSTR DriverName = L"\fdriver";

typedef struct _DRV_MESSAGE_SEND
{
DWORD dwUniqueMessageId;
BOOLEAN fCreate, fRead, fWrite, fExecute;
DWORD dwProcId;
WCHAR wzChildFileName[1024];
} DRV_MESSAGE_SEND, *PDRV_MESSAGE_SEND;

typedef struct _DRV_MESSAGE_RECV { BOOLEAN fAccess; } DRV_MESSAGE_RECV, *PDRV_MESSAGE_RECV;
typedef struct _DRV_TIMER_MESSAGE_RECV { DWORD dwUniqueMessageId; } DRV_TIMER_MESSAGE_RECV, *PDRV_TIMER_MESSAGE_RECV;

typedef struct _STREAM_HANDLE_CONTEXT { BOOLEAN fRequired; } STREAM_HANDLE_CONTEXT, *PSTREAM_HANDLE_CONTEXT;
typedef struct _CREATE_PARAMS { WCHAR wString[0]; } CREATE_PARAMS, *PCREATE_PARAMS;

typedef struct _MAIN_SERVICE_DATA
{
HANDLE ThreadHandle;
PDRIVER_OBJECT pDriverObject;
PFLT_FILTER pFltFilter;
PFLT_PORT pFltServicePort;
PFLT_PORT pFltClientPort;
PEPROCESS pEprocess;
} MAIN_SERVICE_DATA, *PMAIN_SERVICE_DATA;

MAIN_SERVICE_DATA MainServiceData;

typedef struct _TIMER_SERVICE_DATA
{
DWORD dwLastUniqueMessageId;
DWORD dwUniqueMessageId;
KDPC KTimerDpc;
KTIMER KTimer;
} TIMER_SERVICE_DATA, PTIMER_SERVICE_DATA;

TIMER_SERVICE_DATA TimerServiceData;

NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath);
NTSTATUS DriverUnload (FLT_FILTER_UNLOAD_FLAGS FltFilterUnloadFlags);
NTSTATUS DriverInstanceSetup (PCFLT_RELATED_OBJECTS PcFltRelatedObjects, FLT_INSTANCE_SETUP_FLAGS FltInstanceSetupFlags, DEVICE_TYPE DeviceType, FLT_FILESYSTEM_TYPE FltFileSystemType);
NTSTATUS DriverQueryTearDown (PCFLT_RELATED_OBJECTS PcFltRelatedObjects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS FltInstanceQueryTearDownFlags);
FLT_PREOP_CALLBACK_STATUS PreCreate (PFLT_CALLBACK_DATA pFltCallbackData, PCFLT_RELATED_OBJECTS PcFltRelatedObjects, PVOID pContext);
FLT_PREOP_CALLBACK_STATUS SendFileToService(PFLT_CALLBACK_DATA pFltCallbackData, PCFLT_RELATED_OBJECTS PcFltRelatedObjects, PVOID pContext, BOOLEAN fCreate, BOOLEAN fRead, BOOLEAN fWrite);
NTSTATUS ClientServiceConnect (PFLT_PORT pFltClientPort, PVOID pCookie, PVOID pContext, ULONG uContextSize, PVOID pConnCookie);
VOID ClientServiceDisconnect (PVOID pConnCookie);
NTSTATUS ClientServiceMessages (PVOID pCookie, PVOID pIBuffer, ULONG InputLength, PVOID pOBuffer, ULONG OutputLength, PULONG ReturnBufferLength);
NTSTATUS TimerCreate();
VOID TimerDestory();

KDEFERRED_ROUTINE TimerClientServiceDpc;
VOID TimerClientServiceDpc(struct _KDPC kDpc, PVOID pContext, PVOID pArgu1, PVOID pArgu2);

const FLT_OPERATION_REGISTRATION FltOperationRegistrationCallbacks[] = { {IRP_MJ_CREATE, 0, PreCreate, NULL }, {IRP_MJ_OPERATION_END} };
const FLT_CONTEXT_REGISTRATION FltContextRegistration[] = { { FLT_STREAMHANDLE_CONTEXT, 0, NULL, sizeof(STREAM_HANDLE_CONTEXT), ‘corp’ }, {FLT_CONTEXT_END}};
const FLT_REGISTRATION FltRegistration = { sizeof(FLT_REGISTRATION), FLT_REGISTRATION_VERSION, 0, FltContextRegistration, FltOperationRegistrationCallbacks, DriverUnload, DriverInstanceSetup, DriverQueryTearDown, NULL, NULL, NULL, NULL, NULL };

NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING wzString;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
NTSTATUS NtStatus;

NtStatus = FltRegisterFilter(pDriverObject, &FltRegistration, &MainServiceData.pFltFilter);
if(NtStatus != STATUS_SUCCESS) return NtStatus;

NtStatus = FltBuildDefaultSecurityDescriptor(&pSecurityDescriptor, FLT_PORT_ALL_ACCESS);
if(NtStatus != STATUS_SUCCESS) { FltUnregisterFilter(MainServiceData.pFltFilter); return NtStatus; }

RtlInitUnicodeString(&wzString, DriverName);
InitializeObjectAttributes(&ObjectAttributes, &wzString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, pSecurityDescriptor);

NtStatus = FltCreateCommunicationPort(MainServiceData.pFltFilter, &MainServiceData.pFltServicePort, &ObjectAttributes, NULL, ClientServiceConnect, ClientServiceDisconnect, ClientServiceMessages, 1); FltFreeSecurityDescriptor(pSecurityDescriptor);
if(NtStatus != STATUS_SUCCESS) { FltUnregisterFilter(MainServiceData.pFltFilter); return NtStatus; }

NtStatus = FltStartFiltering(MainServiceData.pFltFilter);
if(NtStatus != STATUS_SUCCESS) { FltCloseCommunicationPort(MainServiceData.pFltServicePort); FltUnregisterFilter(MainServiceData.pFltFilter); return NtStatus; }

return STATUS_SUCCESS;
}

NTSTATUS DriverUnload (FLT_FILTER_UNLOAD_FLAGS FltFilterUnloadFlags)
{
FltCloseCommunicationPort(MainServiceData.pFltServicePort);
FltUnregisterFilter(MainServiceData.pFltFilter);

return STATUS_SUCCESS;
}

NTSTATUS DriverInstanceSetup (PCFLT_RELATED_OBJECTS PcFltRelatedObjects, FLT_INSTANCE_SETUP_FLAGS FltInstanceSetupFlags, DEVICE_TYPE DeviceType, FLT_FILESYSTEM_TYPE FltFileSystemType)
{
ASSERT(FltObjects->Filter == MainServiceData.pFltFilter);
if(DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) return STATUS_FLT_DO_NOT_ATTACH;
return STATUS_SUCCESS;
}

NTSTATUS DriverQueryTearDown (PCFLT_RELATED_OBJECTS PcFltRelatedObjects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS FltInstanceQueryTearDownFlags)
{
return STATUS_SUCCESS;
}

FLT_PREOP_CALLBACK_STATUS PreCreate (PFLT_CALLBACK_DATA pFltCallbackData, PCFLT_RELATED_OBJECTS PcFltRelatedObjects, PVOID pContext)
{
return SendFileToService(pFltCallbackData, PcFltRelatedObjects, pContext, TRUE, FALSE, FALSE);
}

FLT_PREOP_CALLBACK_STATUS SendFileToService(PFLT_CALLBACK_DATA pFltCallbackData, PCFLT_RELATED_OBJECTS PcFltRelatedObjects, PVOID pContext, BOOLEAN fCreate, BOOLEAN fRead, BOOLEAN fWrite)
{
PFLT_FILE_NAME_INFORMATION pFltFileNameInformation;
NTSTATUS NtStatus;
PDRV_MESSAGE_SEND pDrvMessageSend;
ULONG ReplyLength;

if(PsIsSystemThread(pFltCallbackData->Thread)) return FLT_PREOP_SUCCESS_NO_CALLBACK;
if(IoThreadToProcess(pFltCallbackData->Thread) == MainServiceData.pEprocess) return FLT_PREOP_SUCCESS_NO_CALLBACK;
if(!NT_SUCCESS(pFltCallbackData->IoStatus.Status) || pFltCallbackData->IoStatus.Status == STATUS_REPARSE) return FLT_PREOP_SUCCESS_NO_CALLBACK;
if(MainServiceData.pFltClientPort == NULL) return FLT_PREOP_SUCCESS_NO_CALLBACK;

NtStatus = FltGetFileNameInformation(pFltCallbackData, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pFltFileNameInformation);
if(NtStatus != STATUS_SUCCESS) return FLT_PREOP_SUCCESS_NO_CALLBACK;

pDrvMessageSend = ExAllocatePoolWithTag(NonPagedPool, sizeof(DRV_MESSAGE_SEND), ‘corp’);
if(pDrvMessageSend == NULL) return FLT_PREOP_SUCCESS_NO_CALLBACK;

FltParseFileNameInformation(pFltFileNameInformation);

pDrvMessageSend->dwUniqueMessageId = 2201;
pDrvMessageSend->fCreate = fCreate;
pDrvMessageSend->fRead = fRead;
pDrvMessageSend->fWrite = fWrite;
pDrvMessageSend->fExecute = FALSE;
pDrvMessageSend->dwProcId = (DWORD) PsGetProcessId(IoThreadToProcess(pFltCallbackData->Thread));
RtlStringCbCopyUnicodeString(pDrvMessageSend->wzChildFileName, 1024, &pFltFileNameInformation->Name);

ReplyLength = sizeof(DRV_MESSAGE_SEND);
NtStatus = FltSendMessage(MainServiceData.pFltFilter, &MainServiceData.pFltClientPort, pDrvMessageSend, sizeof(DRV_MESSAGE_SEND), pDrvMessageSend, &ReplyLength, NULL);
if(NtStatus != STATUS_SUCCESS) NtStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
else
{
if(((PDRV_MESSAGE_RECV)pDrvMessageSend)->fAccess) NtStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
else NtStatus = STATUS_UNSUCCESSFUL;
}

ExFreePoolWithTag(pDrvMessageSend, ‘corp’);
return NtStatus;
}

NTSTATUS ClientServiceConnect (PFLT_PORT pFltClientPort, PVOID pCookie, PVOID pContext, ULONG uContextSize, PVOID pConnCookie)
{
NTSTATUS NtStatus;

DbgPrint(“ClientServiceConnect Called.\n”);
ASSERT(MainServiceData.pFltClientPort == NULL);
ASSERT(MainServiceData.pEprocess == NULL);

MainServiceData.pEprocess = PsGetCurrentProcess();
MainServiceData.pFltClientPort = pFltClientPort;

TimerCreate();

return STATUS_SUCCESS;
}

VOID ClientServiceDisconnect (PVOID pConnCookie)
{
DbgPrint(“ClientServiceDisconnect Called.\n”);
FltCloseClientPort(MainServiceData.pFltFilter, &MainServiceData.pFltClientPort);
MainServiceData.pEprocess = NULL;

TimerDestory();
}

NTSTATUS ClientServiceMessages (PVOID pCookie, PVOID pIBuffer, ULONG InputLength, PVOID pOBuffer, ULONG OutputLength, PULONG ReturnBufferLength)
{
NTSTATUS NtStatus;
DWORD dwUniqueMessageId;

if(pIBuffer != NULL && InputLength >= FIELD_OFFSET(DRV_TIMER_MESSAGE_RECV, dwUniqueMessageId) + sizeof(DWORD))
{
try
{
TimerServiceData.dwLastUniqueMessageId = (DWORD) ((PDRV_TIMER_MESSAGE_RECV) pIBuffer)->dwUniqueMessageId;
DbgPrint(“Message Incoming. [dwLastUniqueMessageId=‘%d’]\n”, TimerServiceData.dwLastUniqueMessageId);
} except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); }
} else return STATUS_INVALID_PARAMETER;

return STATUS_SUCCESS;
}

NTSTATUS TimerCreate()
{
LARGE_INTEGER liTimerInterrupt;
NTSTATUS NtStatus;

pDrvTimerMessageSend = ExAllocatePoolWithTag(NonPagedPool, sizeof(DRV_MESSAGE_SEND), ‘corp’);
if(pDrvTimerMessageSend == NULL) return STATUS_UNSUCCESSFUL;

TimerServiceData.dwLastUniqueMessageId = 0;
TimerServiceData.dwUniqueMessageId = 0;

KeInitializeDpc(&TimerServiceData.KTimerDpc, (PKDEFERRED_ROUTINE)TimerClientServiceDpc, NULL);
KeInitializeTimerEx(&TimerServiceData.KTimer, SynchronizationTimer);

liTimerInterrupt.QuadPart = -(LONGLONG)3
10
1000
1000;
NtStatus = KeSetTimer(&TimerServiceData.KTimer, liTimerInterrupt, &TimerServiceData.KTimerDpc);
if(NtStatus != STATUS_SUCCESS) { DbgPrint(“KeSetTImerEx unfortunately failed.\n”); return NtStatus; }

DbgPrint(“TimerCreate fortunately succeed.\n”);
return STATUS_SUCCESS;
}

VOID TimerDestory()
{
KeCancelTimer(&TimerServiceData.KTimer);
ExFreePoolWithTag(pDrvTimerMessageSend, ‘corp’);
return;
}

VOID TimerClientServiceDpc(PKDPC kDpc, PVOID pContext, PVOID pArgu1, PVOID pArgu2)
{
LARGE_INTEGER liTimerInterrupt;
NTSTATUS NtStatus;
ULONG ReplyLength;

DbgPrint(“Sending Client Ping Request.\n”);

liTimerInterrupt.QuadPart = -(LONGLONG)4
10
1000
1000;
if(TimerServiceData.dwLastUniqueMessageId != TimerServiceData.dwUniqueMessageId)
{
DbgPrint(“Pong request failed.\n”);
//FltCloseClientPort(MainServiceData.pFltFilter, &MainServiceData.pFltClientPort);
} else DbgPrint(“Pong request succeed. [TimerServiceData.dwLastUniqueMessageId=‘%d’]\n”, TimerServiceData.dwLastUniqueMessageId);

if(TimerServiceData.dwUniqueMessageId > 2200) TimerServiceData.dwUniqueMessageId = 0; else TimerServiceData.dwUniqueMessageId++;
pDrvTimerMessageSend->dwUniqueMessageId = TimerServiceData.dwUniqueMessageId;

NtStatus = FltSendMessage(MainServiceData.pFltFilter, &MainServiceData.pFltClientPort, pDrvTimerMessageSend, sizeof(DRV_MESSAGE_SEND), NULL, NULL, &liTimerInterrupt);
if(NtStatus != STATUS_SUCCESS)
{
DbgPrint(“FltSendMessage unfortunately failed.\n”);
}

NtStatus = KeSetTimer(&TimerServiceData.KTimer, liTimerInterrupt, &TimerServiceData.KTimerDpc);
if(NtStatus != STATUS_SUCCESS) { DbgPrint(“KeSetTImerEx unfortunately failed.\n”); return; }

return;
}</ntstrsafe.h></ntifs.h></ntddk.h></suppress.h></dontuse.h></fltkernel.h>