I've followed Microsoft's "Write a Hello World Windows Driver (KMDF)" and wasn't sure how to see the output on WinDbg. After trying to set the Debug Print Filter registry to 0xFFFFFFFF, rebooting and other rain dance solutions, the one thing that worked was enabling DebugView's "Enable Verbose Kernel Output" option. Now, WinDbg shows debug outputs. Its too verbose but at least it's there.
So what did DebugView modify for WinDbg to show more verbose debug output?
I'm running WinDbg attached to a VM from my Windows host with a bridged connection.
TL;DR: it calls a driver to repeatedly call
NtSetDebugFilterState
on all kernel components, so that they are all able to print something on the debug output.Program
Let start with the program itself; there's only one occurrence of the sentence
"Enable Verbose Kernel Output"
:The above code insert the sub-menu into the main menu. What's important here is the the menu ID, namely
0x9C7C
.This menu ID is used only once more here:
The above code calls
DeviceIoControl
and then checks the menu item. The former means the program is actually talking with a device driver.If we remove a bit of code we can see which IOCTL can be sent to the driver:
Since RDX can be either 0 or 1 we end up with (base 10):
Thus:
Looking at the handles opened by
dbgview64.exe
we can see a\Device\dbgv
is currently opened.So the driver is currently loaded from
C:\WINDOWS\system32\Drivers\Dbgv.sys
(or you can extract it from the .rsrc section...).Driver
Looking at the driver, in the driver entry we spot the function used for
IRP_MJ_DEVICE_CONTROL
:Inside that function we have the usual setup before calling the right IOCTL:
Inside the call (
sub_1800017E0
) we have a big switch for the IOCTL, here's the case -2096824260 (case -2096824256 is slightly different):This function is mostly comprised of two loops:
Both calls are on
DbgQueryDebugFilterState
andDbgSetDebugFilterState
(reactos source) which is just a minimal wrapper aroundNtSetDebugFilterState
(reactos source).As far as we can see the debug filter state is queried, saved, and then set for all kernel components (following is the component tables from the kernel, there are a lot of them):
Which finally means that all kernel components are able to print something to the debug output.
Note that the other IOCTL just reset the components masks to what they were before checking the menu in the main program.