Intercepting webcam driver requests - part 2

Hello,

I’ve posted a question on this list some time ago regarding this and received good advice that helped me put together a first working version of the driver I needed.

Here’s my progress:

I’ve implemented this as an “Image” class upper level filter driver. I started off with the MSFT supplied toaster sample’s generic filter driver and then in FilterEvtIoDeviceControl() I do the following:


pIRP = WdfRequestWdmGetIrp(Request);

pSIRP = IoGetCurrentIrpStackLocation(pIRP);

pIRP->UserBuffer;

__try
{
if (KeGetCurrentIrql() == PASSIVE_LEVEL)
{
// Here we get the thread pointer
pEThread = pIRP->Tail.Overlay.Thread;

// Get the process that owns this thread.
pEProcess = IoThreadToProcess(pEThread);

if( NULL != gGetProcessImageFileName )
{
// Get image name
pImageName = gGetProcessImageFileName( PsGetCurrentProcess() );
}

//process and get rid of filter driver control IOCTLs we have sent
if (strstr(“DrvController.exe”, pImageName))
{
pInputBuffer = (PCHAR) pIRP->AssociatedIrp.SystemBuffer;

setUpWhiteList(pInputBuffer);

WdfRequestComplete(Request, STATUS_CANCELLED);

return;
}

if ( Cancel_All || !isInWhiteList(pImageName) )
{
WdfRequestComplete(Request, STATUS_CANCELLED);

KdPrint((“Request from %s cancelled!\n”, pImageName));

return;
}

}
else
KdPrint((“IRQL is not PASSIVE_LEVEL!\n”));

}
__except(EXCEPTION_EXECUTE_HANDLER)
{
//Something went wrong!
status2 = GetExceptionCode();
KdPrint((“Exception: %lx\n”, status2));
}

As you may notice we use DeviceIoControl() on the user mode side to relay special IOCTLs to the filter - these IOCTLs bear as payload a comma delimited string (whitelist) of process names that are allowed to access imaging devices.

This works great for us but I would very much appreciate any comments you have regarding errors or oversights you find.

Also, we are now thinking of adding an “on-the-fly” whitelisting feature whereby when the driver encounters IRPs coming in from a process with an unknown name it somehow communicates that to our user mode app and that prompts the user for input (i.e. either whitelist or block).

I’ve been thinking that the communication from kernel mode to user mode needed could be implemented as a shared event (as explained in your article here: http://www.osronline.com/article.cfm?id=108) although I am still unsure as to how I would pass the name of the process in question back to user mode (perhaps like this: http://www.osronline.com/article.cfm?article=39).

Still, the biggest problem, I think, is what the driver should do with the IRPs in question in the meantime. I currently tend to think that I should keep them queued until the user responds or a timeout (that defaults to block) occurs, although I am kinda unsure right now as to how exactly this could be done - perhaps like this? http://msdn.microsoft.com/en-us/library/windows/hardware/ff563772(v=vs.85).aspx

Thank you very much in advance for any help and suggestions.

Merry Xmas all!

Alex

Don’t use a shared event, just have your control app pend an ioctl with your driver. Complete the ioctl with the new to be approved application name in the pended IOCtl’s output buffer when you want approval. The app sends a diff ioctl with the answer to allow or not

d


From: xxxxx@gmail.commailto:xxxxx
Sent: ?12/?21/?2012 1:22 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: [ntdev] Intercepting webcam driver requests - part 2

Hello,

I’ve posted a question on this list some time ago regarding this and received good advice that helped me put together a first working version of the driver I needed.

Here’s my progress:

I’ve implemented this as an “Image” class upper level filter driver. I started off with the MSFT supplied toaster sample’s generic filter driver and then in FilterEvtIoDeviceControl() I do the following:

---------------------------------
pIRP = WdfRequestWdmGetIrp(Request);

pSIRP = IoGetCurrentIrpStackLocation(pIRP);

pIRP->UserBuffer;

__try
{
if (KeGetCurrentIrql() == PASSIVE_LEVEL)
{
// Here we get the thread pointer
pEThread = pIRP->Tail.Overlay.Thread;

// Get the process that owns this thread.
pEProcess = IoThreadToProcess(pEThread);

if( NULL != gGetProcessImageFileName )
{
// Get image name
pImageName = gGetProcessImageFileName( PsGetCurrentProcess() );
}

//process and get rid of filter driver control IOCTLs we have sent
if (strstr(“DrvController.exe”, pImageName))
{
pInputBuffer = (PCHAR) pIRP->AssociatedIrp.SystemBuffer;

setUpWhiteList(pInputBuffer);

WdfRequestComplete(Request, STATUS_CANCELLED);

return;
}

if ( Cancel_All || !isInWhiteList(pImageName) )
{
WdfRequestComplete(Request, STATUS_CANCELLED);

KdPrint((“Request from %s cancelled!\n”, pImageName));

return;
}

}
else
KdPrint((“IRQL is not PASSIVE_LEVEL!\n”));

}
__except(EXCEPTION_EXECUTE_HANDLER)
{
//Something went wrong!
status2 = GetExceptionCode();
KdPrint((“Exception: %lx\n”, status2));
}
----------------------------------

As you may notice we use DeviceIoControl() on the user mode side to relay special IOCTLs to the filter - these IOCTLs bear as payload a comma delimited string (whitelist) of process names that are allowed to access imaging devices.

This works great for us but I would very much appreciate any comments you have regarding errors or oversights you find.

Also, we are now thinking of adding an “on-the-fly” whitelisting feature whereby when the driver encounters IRPs coming in from a process with an unknown name it somehow communicates that to our user mode app and that prompts the user for input (i.e. either whitelist or block).

I’ve been thinking that the communication from kernel mode to user mode needed could be implemented as a shared event (as explained in your article here: http://www.osronline.com/article.cfm?id=108) although I am still unsure as to how I would pass the name of the process in question back to user mode (perhaps like this: http://www.osronline.com/article.cfm?article=39).

Still, the biggest problem, I think, is what the driver should do with the IRPs in question in the meantime. I currently tend to think that I should keep them queued until the user responds or a timeout (that defaults to block) occurs, although I am kinda unsure right now as to how exactly this could be done - perhaps like this? http://msdn.microsoft.com/en-us/library/windows/hardware/ff563772(v=vs.85).aspx

Thank you very much in advance for any help and suggestions.

Merry Xmas all!

Alex


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</mailto:xxxxx></mailto:xxxxx>

Thank you Doron

yes - completing a pending IOCtl when an IRP from an unknown app comes in and then waiting for a new one with the answer sounds like a great way to do it. I am thinking this approach implies two internal queues (one for the IOCtls from the control app and one for the rest of the IRPs) and asynchronous (or non-serialized) I/O?

Looking more into what you suggested I realize this is basically a technique known as “Inverted Call Model” that has been advocated by OSR and yourself for quite some time. There’s an OSR NT Insider article about it here: http://www.osronline.com/article.cfm?id=94

I will look into this and other related resources and post the specifics of my implementation once it’s working.

Cheers

xxxxx@gmail.com wrote:

I’ve implemented this as an “Image” class upper level filter driver. I started off with the MSFT supplied toaster sample’s generic filter driver and then in FilterEvtIoDeviceControl() I do the following:

As you may notice we use DeviceIoControl() on the user mode side to relay special IOCTLs to the filter - these IOCTLs bear as payload a comma delimited string (whitelist) of process names that are allowed to access imaging devices.

This works great for us but I would very much appreciate any comments you have regarding errors or oversights you find.

Well, the whole concept is flawed, because process names are not
secure. I can make my process name be whatever I want.

__try / __except is not as generically useful as you seem to think.
Nothing here is going to trigger an exception.

I’ve been thinking that the communication from kernel mode to user mode needed could be implemented as a shared event (as explained in your article here: http://www.osronline.com/article.cfm?id=108) although I am still unsure as to how I would pass the name of the process in question back to user mode (perhaps like this: http://www.osronline.com/article.cfm?article=39).

In general, the “inverted call” concept is the best way to do this.
Have the user-mode monitor app submit an ioctl that gets pended forever
in the driver. When the driver needs an answer, it completes the IRP
and waits for a response.

The problem with a shared event by itself is that there’s no way to
return any state information with it. The IRP can have an event
associated with it (you’ll want it to be OVERLAPPED), so you get the
best of both worlds there.

Still, the biggest problem, I think, is what the driver should do with the IRPs in question in the meantime. I currently tend to think that I should keep them queued until the user responds or a timeout (that defaults to block) occurs, although I am kinda unsure right now as to how exactly this could be done -

If you return without calling WdfRequestComplete, then KMDF will pend
the request for you. You would want to put it in a queue somewhere so
that you can find it later to complete or cancel it, once you get an
answer from the app.


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

Hi Tim,

Well, the whole concept is flawed, because process names are not
secure. I can make my process name be whatever I want.

Indeed. It is practically impossible to stop rogue users/processes from having their way with a PC. The value that such software provides is more related to protecting you from inadvertent webcam access by a legitimate app at a known path. For instance you could keep the whitelist empty and manually authorize each access when you need to use the cam or in case you’re utilizing the whitelist it would protect you from newly installed webcam accessing apps whose default operation and “habits” are still unknown to you.

__try / __except is not as generically useful as you seem to think.
Nothing here is going to trigger an exception.

yes, I put it there seeking refuge from the bombardment of BSODs that rained on me until I figured out it was not checking the IRQL before attempting certain things that was causing it. I decided to leave it like that just in case something else goes wrong. Do you think it is better to remove it? My impression is that it can save you from BSODs sometimes.

If you return without calling WdfRequestComplete, then KMDF will pend
the request for you. You would want to put it in a queue somewhere so
that you can find it later to complete or cancel it, once you get an
answer from the app.

Thank you for that - this is exactly what I will be trying to do and I will get back to the list once I get a chance to work on it and get some good results.

I also wanted to give much deserved kudos to both you and Doron as well as this wonderful list that I am sure is a soothing oasis for many people venturing into the world of system software. I am currently working on a number of projects involving a bit of driver work (this, some WFP and a UMDF driver) and everywhere I look your names pop up. Your contributions to this community are both humbling and inspiring.

Cheers,
Alex

you don’t want the extraneous __try/__except blocks. they don’t save you from BSODs, rather if used improperly (and this use is improper) they HIDE BSODs and make the problem much worse. the user can lose more data, more corruption occurrs instead of immediately stopping, etc. you want to stop when you hit an error BSOD, not ignore it

d


From: xxxxx@lists.osr.com [xxxxx@lists.osr.com] on behalf of xxxxx@gmail.com [xxxxx@gmail.com]
Sent: Tuesday, December 25, 2012 11:31 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Intercepting webcam driver requests - part 2

Hi Tim,

Well, the whole concept is flawed, because process names are not
secure. I can make my process name be whatever I want.

Indeed. It is practically impossible to stop rogue users/processes from having their way with a PC. The value that such software provides is more related to protecting you from inadvertent webcam access by a legitimate app at a known path. For instance you could keep the whitelist empty and manually authorize each access when you need to use the cam or in case you’re utilizing the whitelist it would protect you from newly installed webcam accessing apps whose default operation and “habits” are still unknown to you.

__try / __except is not as generically useful as you seem to think.
Nothing here is going to trigger an exception.

yes, I put it there seeking refuge from the bombardment of BSODs that rained on me until I figured out it was not checking the IRQL before attempting certain things that was causing it. I decided to leave it like that just in case something else goes wrong. Do you think it is better to remove it? My impression is that it can save you from BSODs sometimes.

If you return without calling WdfRequestComplete, then KMDF will pend
the request for you. You would want to put it in a queue somewhere so
that you can find it later to complete or cancel it, once you get an
answer from the app.

Thank you for that - this is exactly what I will be trying to do and I will get back to the list once I get a chance to work on it and get some good results.

I also wanted to give much deserved kudos to both you and Doron as well as this wonderful list that I am sure is a soothing oasis for many people venturing into the world of system software. I am currently working on a number of projects involving a bit of driver work (this, some WFP and a UMDF driver) and everywhere I look your names pop up. Your contributions to this community are both humbling and inspiring.

Cheers,
Alex


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

Doron Holan wrote:

you don’t want the extraneous __try/__except blocks. they don’t save you from BSODs, rather if used improperly (and this use is improper) they HIDE BSODs and make the problem much worse. the user can lose more data, more corruption occurrs instead of immediately stopping, etc. you want to stop when you hit an error BSOD, not ignore it

I saw this generalized many years ago as a very handy rule: “Never
check for an exception that you aren’t prepared to handle.”


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

yeah, better deal with any problems early than late.

Thanks!