Building Drivers For Different Versions of Windows Revisited.

I think most of us would prefer to have one set of driver binaries, a 32bit
version and a 64bit version, that run on all windows releases we need to
support. Typically that would be Windows 7 and later releases, and their
server equivalents.

The conventional wisdom is to “build for the oldest release you need to
support”. And that is a fine answer to the problem for most situations. As
long as you don’t need any data structures or interfaces in later
platforms, this is definitely the best choice.

But what if you do? The OS has changed substantially since the Win7 WDK was
published. You might just need to use features in up rev releases of
windows, or worse, you could have bugs that are caused by using older
interfaces and data structures in newer releases.

The MSDN docs offer a solution to your problem.
https:

If you want your kernel-mode driver to run on multiple versions of Windows
> and dynamically determine the features that are available to the driver,
> build the driver using the build configuration for the most recent version
> of the operating system. For example, if you want your driver to support
> all versions of Windows starting with Windows 7, but to use certain
> features that were first available in Windows 8.1 when your driver is
> running on Windows 8.1 or later versions of the operating system, specify
> Windows 8.1 (Win8.1) as the target configuration.

The docs then go on to explain that you should use
RtlIsNtDdiVersionAvailable to determine what platform your driver is
executing on and consequently which interfaces and data structures are
available. The docs then continue on and note that you need to link with
BufferOverflowK.lib if you are gfoing to support Win7. Unfortunately, that
is insufficient, and worse the examples of how to link in this library are
either wrong or a real bad idea.

First the insufficiency. Huh Knew you needed memcmp? No really Huh knew. Right
here on NtDev. http: Woojung
Huh ran straightt into the memcmp problem and was immediately attacked by
the purity police for daring to note that he was using ZwLoadDriver,
advised repeatedly to link with BufferoverflowK.lib, which he was already
doing, told to go build against win7 instead, advised incorrectly that a
win8 driver cannot load in a win7 os because of pe header checking, and
pointed repeatedly to other ways of loading his driver. None of which, in
classic NtDev mode, addressed his actual problem, which was that win8 and
later provide memcmp as part of ntoskrnl while win7 and earlier don’t.

Eventually Huh grew tired of NtDev blood sport and isolated his use of
memcmp to IsEqualGUID and just stopped using it, problem solved. For Huh.

There is of course a more useful solution. If you go look at the set of
kernel mode static libraries available in the WDK you will find “C:\Program
Files (x86)\Windows Kits\10\Lib\10.0.14393.0\km\x86\memcmp.lib” for
example. Gosh I just wonder if that might provide the missing memcmp?

So months later Huh, there is your answer.

Now back to the MSDN DOCS on how to build a win8 driver that runs on win7.
Their first suggestion works, but is just an awful hacky thing to do, so
don’t do that. They suggest just hard-coding the path to BufferOverflowK in
a (presumably scripted) invocation of msbuild. Like this:

msbuild /p:KernelBufferOverflowLib=“C:\Program Files (x86)\Windows
> Kits\8.1\Lib\win8\km\x64\BufferOverflowK.lib” /p:platform=x64
> /p:Configuration=“Win8 Release” myDriver.sln

I’ll give you extra credit if you don’t know why that is A Real Bad Idea.

Following up on the Real Bad Idea was the suggestion to incorrectly modify
your project file by tossing in

> $(DDK_LIB_PATH)\BufferOverflowK.lib
>

at a point in project file parsing when $(DDK_LIB_PATH) is undefined:

The elements must appear in the driver project
> file before the element that imports Microsoft.Cpp.props, which imports the
> tool set.

It is the importing of the toolset that defines DDK_LIB_PATH. The linker
will silently ignore BufferOverflowK.lib, which is prefixed by a null
DDK_LIB_PATH, and badness will ensue. Instead you can just add
$(DDK_LIB_PATH)\BufferOverflowK.lib
as yet another static library, alongside memcmp.lib, in the linker section
later on, as in

> >> Condition=“‘$(Configuration)|$(Platform)’==‘Release|ARM64’”>
>
>

>
>
>> $(DDK_LIB_PATH)\memcmp.lib;$(DDK_LIB_PATH)\BufferOverflowK.lib;%(AdditionalDependencies)
>
>
>
>
Mark Roddy</http:></https:>

We used to try to have a single binary support different versions, but now we bit the bullet and just build different flavors.

Yup.

Signing requirements are making the “one binary, runs everywhere” model increasingly untenable.

It’s all a bit sad… but we’re getting used to that feeling…

P