Last reviewed and updated: 10 August 2020
In looking at the history of Windows driver development, there are some significant highpoints. Windows 2000, for example, introduced Driver Verifier which is the single greatest gift ever to be bestowed upon driver writers. This set the bar pretty high for what the next next Windows release, Windows XP, would bring. But I think we can all agree that XP really delivered. After all, it introduced three awesome features:
- The triumphant return of Microsoft Bob’s Rover the dog
- A complete driver build environment. Remember what a mess it was when all you got were the headers and the libs from the WDK and the compiler and linker came from Visual Studio? Oh, wait…
- Automatic driver replacement with KDFiles
The first two features are now drifting off into history, but driver replacement using KDFiles is still supported and is, in fact, even more useful today than it was when it was first introduced all those years ago (we’ll get to why later). Unfortunately, we find that people either don’t know about KDFiles or tried it but gave up after battling with the syntax.
In this article, we’ll revisit the need for KDFiles and provide a bulletproof method for determining the correct mapping syntax for driver replacement.
Why Driver Mapping?
Developing drivers on Windows requires two machines: a host machine for development and a target machine for running the driver under test. We never, ever want to run our driver on our development machine for fear of corrupting our system from the incessant crashing of our buggy driver.
This then leads to the practical problem of copying a driver that we built on our development machine to our target machine for testing. Without KDFiles, there is no maximally convenient way to do this. You can copy the file over the network or via a USB drive, each of which has their own annoyances. Virtual Machine debugging has the benefit of drag and drop, but that assumes that VMware hasn’t suddenly decided that it doesn’t want to do that anymore. And, of course, all of these assume that you actually remember to copy the file over. Nothing kills the satisfaction of fixing a bug more than rebuilding your driver just to restart your tests using the old version.
KDFiles provides the ability to automatically update a driver on the target with a new file from the host each time the driver loads. This means you can always be running the latest version of your driver on the target without any additional post build steps. All you need to do is use the .kdfiles command (entered at the WinDbg command prompt) to provide WinDbg with a “replacement map”, indicating which drivers on the target should be replaced by files from the host. The target O/S and WinDbg will then do the work to copy the updated driver over the kernel debug connection on each driver load.
Registering Replacements with Mapping Files
There are a couple of different ways that you can indicate a replacement mapping. The original way is through the use of a Mapping File. This is a simple text file, created on the same machine on which you’re running WinDbg (the “host” machine), with the following syntax:
map
<module-to-replace-on-the-Target>
<Path-to-the-replacement-on-the-Host>
The Mapping File can contain multiple mappings, each of which is preceded by the mandatory map keyword. So, one example of a mapping file might be:
map
\Systemroot\system32\drivername.sys
C:\MyNewDriver\mydriver0031.sys
The mapping file above would replace “drivername.sys” on the target with “mydriver0031.sys” from the host. Pretty useful, right?
The first component of the mapping file is simple. It’s the word “map” on a line by itself. I think most people can get that right without too much help.
The second component of the mapping file, the “old driver” specification, can be tricky one. This is where you specify the module path of the driver on the target, which is not necessarily the same as any normal human-understandable driver image’s location on disk. Some examples of common, equally valid module paths for the “old driver” specification are:
- \Windows\System32\drivername.sys
- \SystemRoot\System32\drivername.sys
- \??\C:\Windows\System32\drivername.sys
The path used greatly depends on how the driver was installed and the current data of its ImagePath value. This effectively makes it impossible to know a priori what the module path of the driver will be on the target. This has caused a lot of people who know about “.kdfiles” to give up using it, which is too bad. Because it really is useful.
Fortunately, starting in Windows 10, the syntax for the “old driver” path has been significantly improved. The full path no longer needs to be specified, and even the file extension can be omitted. So, if you want to replace “\Systemroot\system32\drivername.sys” any of the following will work:
- drivername
- DRIVERNAME
- drivername.sys
- \Windows\System32\drivername.sys
And they say things never get better with time. Ha!
But Wait… It Gets Even Easier
Also starting in Windows 10, the debugger team introduced another improvement. You can skip creating the mapping file entirely, and just take advantage of the enhancements to matching for the “old driver” specification. You can do this using the “-m” option on the .kdfiles command line as follows:
kd> .kdfiles -m drivername C:\MyNewDriver\mydriver0031.sys
That’s all you need to setup the replacement of “drivername.sys” on the target “mydriver0031.sys” on the host.
For sanity, we can execute .kdfiles again with no parameters to confirm the mapping:
kd> .kdfiles
drivername ->C:\MyNewDriver\mydriver0031.sys
The next time we load the driver, we should see output in the debugger indicating that the updated file is being “pulled” from the host to the target:
KD: Accessing 'C:\MyNewDriver\mydriver0031.sys' ...
KdPullRemoteFile: About to overwrite... drivername.sys and preallocate to 2670
....
Voila! We’re now running the version of the driver that was located in the specified directory on our host.
If at any point we want to clear the current set of mappings, we can use the /c switch to the .kdfiles command. Beware though that KDFiles overwrites the driver image on the target, so clearing the mapping does not actually revert the version of the driver.
The Boot Debugger Supports KDFiles Too!
We mentioned at the start that KDFiles is now even more useful, but how is that? Well, it turns out that the Boot Debugger also supports driver replacement. This means that you can automatically update your boot start drivers, which are otherwise a pain to update during development. To do this, you simply need to make sure that the boot debugger is enabled on your target machine using bcdedit:
bcdedit.exe /set bootdebug on
And provide a mapping for the boot start driver in your mapping file.
Conclusion
KDFiles is one of those things that we would now have a hard time living without, though it certainly isn’t entirely user friendly in getting configured. If you’ve never heard of it before, you’re certainly in for a treat. If you have tried but gave up, give it another shot with the steps we outlined in this article and let us know how it goes!