IoRegisterPlugPlayNotification and ksfilter drivers

I’m trying to track the mskssrv.sys driver device, which is loaded and unloaded dynamically by the OS. I know the following about it:

  • It’s mentioned in ksfilter.inf, along with mspclock, mspqm and mstee.
  • Device Interface GUID: KSNAME_Server = {3c0d501a-140b-11d1-b40f-00a0c9223196}.
  • Device Interface Path: \\?\root#system#0000#{3c0d501a-140b-11d1-b40f-00a0c9223196}\{96e080c7-143c-11d1-b40f-00a0c9223196}&{3c0d501a-140b-11d1-b40f-00a0c9223196}, or SW\{96E080C7-143C-11D1-B40F-00A0C9223196}\{3C0D501A-140B-11D1-B40F-00A0C9223196} (not sure if the two are equivalent).
  • It’s loaded as an upper driver of \Driver\swenum, device \Device\KSENUM#0000000b.

So, I tried using IoRegisterPlugPlayNotification with EventCategoryDeviceInterfaceChange and KSNAME_Server, passing the PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES flag. But it looks like the device is considered to be always loaded. Also, if I use IoCreateFile on it and it’s unloaded, it gets loaded.

How can I get a load notification for mskssrv? How can I check whether it’s loaded at a given time? Thanks.

User-mode or kernel-mode?

User-Mode: here.

Kernel-mode: here.

Peter

Thank you for the reply Peter. I need this information in Kernel Mode. As I wrote, I tried using IoRegisterPlugPlayNotification, but it didn’t work as I hoped:

  • If the device is unloaded and I use INCLUDE_EXISTING_INTERFACES, my callback is called right away even though the device is unloaded.
  • When it’s being loaded, I don’t get a notification.

That makes me think that it’s considered to be always loaded, as I wrote. So I’d like to know if there’s an alternative solution? Thanks.

Paul_Jackson wrote:

* If the device is unloaded and I use INCLUDE_EXISTING_INTERFACES, my callback is called right away even though the device is unloaded.
* When it’s being loaded, I don’t get a notification.

That makes me think that it’s considered to be always loaded, as I wrote. So I’d like to know if there’s an alternative solution?

Just to be pedantic here, the PNP notifications do not tell you when a
driver is loaded or unloaded or when a new instance is created or
destroyed.  They tell you when device interface is registered or
unregistered.  The difference is important.

I’m not saying it’s the case here, but one can imagine an implementation
where this driver is loaded early in boot time, and activates its device
interface once, rather than every time it gets added to a device stack. 
That would be contrary to the usual philosophy of device interfaces, but
it’s not impossible.

Do you see windbg notifications telling you the driver .sys file is
actually being loaded and unloaded?

They tell you when device interface is registered or unregistered.

Well, to be pedantic, they tell you when a device interface is enabled or disabled – as indeed the device interface could already be registered but not currently enabled.

Sorry… splitting hairs B)

one can imagine an implementation where this driver is loaded early in boot time…

Even more so, one could imagine a driver’s management instance being instantiated somehow and then only once. Perhaps a root enumerated instance.

If the device is unloaded and I use INCLUDE_EXISTING_INTERFACES, my callback is called right away even though the device is unloaded

You’re telling me that you get a callback that tells you a device interface is enabled, but there’s no device object associated with it? Sorry, I don’t believe that. What sym link do you get, and to what device object does it resolve when you try to open it?

I guess my overall point is that it seems that the device interface GUID is not tracking what you want it to be tracking. So, using that is probably not going to work if you want to know about the arrival and departure of mskssrv as an upper filter instance.

If you can live with knowing when the particular sys file is loaded/started, you could use PsSetLoadImageNotifyRoutine?

Peter

Do you see windbg notifications telling you the driver .sys file is
actually being loaded and unloaded?

Yes

What sym link do you get

\??\ROOT#SYSTEM#0000#{3c0d501a-140b-11d1-b40f-00a0c9223196}\{96E080C7-143C-11D1-B40F-00A0C9223196}&{3C0D501A-140B-11D1-B40F-00A0C9223196}

Once I call IoCreateFile on that sym link, the sys file is being loaded and the device is being created.

device interface GUID is not tracking what you want it to be tracking

Is there a way to find whether there’s another device interface GUID which tracks what I want?

If you can live with knowing when the particular sys file is loaded/started, you could use PsSetLoadImageNotifyRoutine?

That’s an option. I thought about it, but hoped there might be a cleaner solution. I’ll try that.

Once I call IoCreateFile on that sym link, the sys file is being loaded and the device is being created.

Hmmm. Well, no. Windows doesn’t load drivers when a device is opened. Rather, the driver has to already be there for the device to be opened successfully. And I’m not sure you want to use IoCreateFile for this…you’d probably want to call WdfIoTargetOpen or IOGetDeviceObjectPointer.

You didn’t tell me anything about the dev node that gets opened from the sym link. Get the device object pointer and take a look at it in the debugger and figure out what’s going on.

In any case, with all due respect, I think the basic issue might be that you don’t have a completely clear picture of the drivers and devices that are involved. This sort of “exploring” can be pretty challenging.

Is there a way to find whether there’s another device interface GUID which tracks what I want?

It can be difficult, and there’s no guarantee that there IS one. I think your first step would be understanding what’s loaded, where, and how. You need to have a really clear understanding of the PDOs, FDOs, and filters involved and how they get instantiated. Spending some quality time in WinDbg will be required.

Peter

Once I call IoCreateFile on that sym link, the sys file is being loaded and the device is being created.

OMG…

I would rather advise you to start it all over from the very,very,very beginning - the above statement immediately reveals that your current level of understanding of Windows driver basics is critically close to zero. Assuming that a driver is not loaded at the moment, who do you think is going to be the target of IRP_MJ_CREATE that IoCreateFile() will eventually end up sending??? This applies to any driver in existence.

Go to MSDN, and read carefully all the basic stuff - what the mechanisms of loading and unloading drivers are; what DriverEntry() and DriverUload()(if any) routines have to do; in which particular situation any particular IRP_MJ_XXXX gets sent to a driver; etc,etc,etc.
Checking WDK samples is not going to harm you either…

Anton Bassov

the driver has to already be there for the device to be opened successfully

Perhaps the parent driver is always there, and the child driver is loaded on demand as an upper driver?

you’d probably want to call WdfIoTargetOpen or IOGetDeviceObjectPointer

I’m using IoCreateFile + ObReferenceObjectByHandle + IoGetRelatedDeviceObject. Would IoGetDeviceObjectPointer be a better alternative? Why?

You didn’t tell me anything about the dev node that gets opened from the sym link

What do you mean by the

Thanks for the help. You’re right that I don’t have a completely clear picture. The whole kernel world is relatively new to me.

Assuming that a driver is not loaded at the moment, who do you think is going to be the target of IRP_MJ_CREATE that IoCreateFile() will eventually end up sending???

Well, as a matter of fact it works. I assume a swenum.sys device receives the IRP_MJ_CREATE, and it loads mskssrv.sys and creates the appropriate device.

I’m using IoCreateFile + ObReferenceObjectByHandle + IoGetRelatedDeviceObject

So… what device are you opening? What drivers are attached above it and below it?

We’re not asking you to cure cancer here… we’re asking you to type a couple of commands in the debugger and tell us what you see. You’ve got to be willing to do at least that much if we’re going to be able to help you.

Peter

I see that my message got truncated in “What do you mean by the”, sorry.

So, here’s what VirtualTree shows for mskssrv:
https://i.imgur.com/RvD7w1X.png

Here’s swenum, when mskssrv is loaded:
https://i.imgur.com/mQT0P2A.png

Here’s swenum, when mskssrv is not loaded:
https://i.imgur.com/25UK4zN.png

When accessing the mentioned sym link that I get, I end up getting the ksthunk device.

I hope that’s the information you were asking for.

It looks like PsSetLoadImageNotifyRoutine can indeed work. My only concern is that the OS limits the amount of subscribers to 8. But for now that’s the only solution I have.

Well, as a matter of fact it works.

Well, the above statement simply confirms my previous post. Basically, you claim the following :

  1. You call IoCreateFile() on a symlink that corresponds to the name of a nonexistent, at the moment, device - its driver is not even loaded at the moment
  2. As a result, the driver in question gets loaded, and the target device gets created

The above scenario simply contradicts everything that I know about Windows drivers in so far…

I assume a swenum.sys device receives the IRP_MJ_CREATE, and it loads mskssrv.sys and creates the appropriate device.

If we were speaking about sending an IRP the device that gets created (and, hence,owned) by swenum.sys, everything would
make a perfect sense, at least from the logical standpoint. Certainly, this is still not the way Windows drivers actually work,
but, unlike your suggestions, at least it does not throw the common sense and conventional wisdom out of the window.
However, according to you, it is mskssrv.sys and not swenum.sys who is supposed to create it. Why on Earth would swenum.sys even receive IRP_MJ_CREATE then??? Has it ever occurred to you to think this way?

It’s loaded as an upper driver of \Driver\swenum, device \Device\KSENUM#0000000b.

Well, this part explains everything. The key point here is that we are speaking about PnP drivers. If it is an “upper driver” for something
(i.e. happens to be a filter or FDO), it attaches its device to the stack that is built on top of some PDO. A device that it attaches to the stack is unnamed. Besides this, it may also create named devices as well . They may act as PDOs (i.e the driver in question acts as a bus driver) , as well as standalone control devices that are not a part any PnP stack.

Judging from your description, a device that your symbolic link points to is a named PDO that has been created by some bus driver (it may or may not be swenum.sys, depending on the role of the latter in the particular PnP stack), and not by mskssrv.sys as you seem to believe.
The latter driver gets dynamically loaded and unloaded by PnP in response to IoInvalidateDeviceRelations() call on the target device
that gets made by its parent bus driver, and not in response to your IoCreateFile() one as you seem to believe…

Therefore, you simply give a wrong interpretation of the things that you observe, and provide us with a misleading information…

Anton Bassov

You’re not using the debugger, are you?

Now we know why you can’t figure out what’s going on.

Issue closed.

Peter

Thank you for helping me getting the full picture. @anton_bassov, you’re right in your explanation. That’s also what I see being called - NtCreateFile calls swenum’s IRP_MJ_CREATE dispatcher, which in turn creates a device and calls IoInvalidateDeviceRelations:

kd> k
 # Child-SP          RetAddr           Call Site
00 fffffb82`24c0d2a8 fffff80f`bbfcdc4f nt!IoCreateDevice
01 fffffb82`24c0d2b0 fffff80f`bbfcea98 ks!CreatePdo+0xa7
02 fffffb82`24c0d3c0 fffff80f`bc1672ef ks!KsServiceBusEnumCreateRequest+0x208
03 fffffb82`24c0d400 fffff800`468a3e69 swenum!DispatchCreate+0x4f
04 fffffb82`24c0d430 fffff800`46ccfba3 nt!IofCallDriver+0x59
05 fffffb82`24c0d470 fffff800`46cff7eb nt!IopParseDevice+0x773
06 fffffb82`24c0d640 fffff800`46ccdcdf nt!ObpLookupObjectName+0x73b
07 fffffb82`24c0d820 fffff800`46cca045 nt!ObOpenObjectByNameEx+0x1df
08 fffffb82`24c0d960 fffff800`46cc97a9 nt!IopCreateFile+0x3f5
09 fffffb82`24c0da00 fffff800`469c5743 nt!NtCreateFile+0x79
0a fffffb82`24c0da90 00007ffa`2d62b444 nt!KiSystemServiceCopyEnd+0x13
0b 00000049`e8a7f0b8 00007ffa`2a434be8 0x00007ffa`2d62b444
0c 00000049`e8a7f0c0 00000000`00000000 0x00007ffa`2a434be8

kd> k
 # Child-SP          RetAddr           Call Site
00 fffffb82`266bc3b8 fffff80f`bbfceb58 nt!IoInvalidateDeviceRelations
01 fffffb82`266bc3c0 fffff80f`bc1672ef ks!KsServiceBusEnumCreateRequest+0x2c8
02 fffffb82`266bc400 fffff800`468a3e69 swenum!DispatchCreate+0x4f
03 fffffb82`266bc430 fffff800`46ccfba3 nt!IofCallDriver+0x59
04 fffffb82`266bc470 fffff800`46cff7eb nt!IopParseDevice+0x773
05 fffffb82`266bc640 fffff800`46ccdcdf nt!ObpLookupObjectName+0x73b
06 fffffb82`266bc820 fffff800`46cca045 nt!ObOpenObjectByNameEx+0x1df
07 fffffb82`266bc960 fffff800`46cc97a9 nt!IopCreateFile+0x3f5
08 fffffb82`266bca00 fffff800`469c5743 nt!NtCreateFile+0x79
09 fffffb82`266bca90 00007ffa`2d62b444 nt!KiSystemServiceCopyEnd+0x13
0a 000000e3`5f57f3e8 00007ffa`2a434be8 0x00007ffa`2d62b444
0b 000000e3`5f57f3f0 00000000`00000000 0x00007ffa`2a434be8

IoInvalidateDeviceRelations probably causes mskssrv to be loaded in a worker thread. Then a device is created:

kd> k
 # Child-SP          RetAddr           Call Site
00 fffffb82`2536b518 fffff800`48dc8048 nt!IoCreateDevice
01 fffffb82`2536b520 fffff800`4696e013 MSKSSRV!PnpAddDevice+0x38
02 fffffb82`2536b570 fffff800`46e09e59 nt!PpvUtilCallAddDevice+0x3b
03 fffffb82`2536b5b0 fffff800`46dd576f nt!PnpCallAddDevice+0x59
04 fffffb82`2536b640 fffff800`46dd49b1 nt!PipCallDriverAddDevice+0x813
05 fffffb82`2536b7f0 fffff800`46dd12b2 nt!PipProcessDevNodeTree+0x1f1
06 fffffb82`2536ba70 fffff800`46950beb nt!PiProcessReenumeration+0x82
07 fffffb82`2536bac0 fffff800`468c0b05 nt!PnpDeviceActionWorker+0x1eb
08 fffffb82`2536bb80 fffff800`4693b2d7 nt!ExpWorkerThread+0xf5
09 fffffb82`2536bc10 fffff800`469bc516 nt!PspSystemThreadStartup+0x47
0a fffffb82`2536bc60 00000000`00000000 nt!KiStartSystemThread+0x16

Now that we know this, perhaps you have an idea about getting a notification for mskssrv being loaded other than using PsSetLoadImageNotifyRoutine?

only concern is that the OS limits the amount of subscribers to 8

Not since XP SP 1… and XP SP 3 was the last service pack. You can be pretty sure anyone running XP is at least running XP SP 2or SP 3. Even SP2 was a hot mess of bugs (I’m doing a project targeted to XP right now, as a matter of,fact).

Peter

OK, so for now, PsSetLoadImageNotifyRoutine it is. I verified and it works. The only missing piece: is there a straightforward way to check whether mskssrv.sys is loaded at a given time? I guess I’m looking for an equivalent of GetModuleHandle() != NULL for kernel mode.

The only missing piece: is there a straightforward way to check whether mskssrv.sys is loaded at a given time? I guess I’m looking for an >equivalent of GetModuleHandle() != NULL for kernel mode.

AuxKlibQueryModuleInformation() is your friend - it will give you the list of the loaded modules with the start/end address of each module

Anton Bassov

Paul_Jackson wrote:

Thank you for helping me getting the full picture. @anton_bassov, you’re right in your explanation. That’s also what I see being called - NtCreateFile calls swenum’s IRP_MJ_CREATE dispatcher, which in turn creates a device and calls IoInvalidateDeviceRelations:

IoInvalidateDeviceRelations probably causes mskssrv to be loaded in a worker thread. Then a device is created:

Now that we know this, perhaps you have an idea about getting a notification for mskssrv being loaded other than using PsSetLoadImageNotifyRoutine?

I think what others have been trying to point out is that this event
might not trigger the LOADING of mskssrv.  If it were already present in
memory, then the only action being taken here is the creation of a new
device object for the existing mskssrv image to service.