zydis: Errors while using Zydis.lib in windows driver

Quick fixes for:

  • stdint.h not found -> just add a copy from visual studio
  • unresolved external symbol __imp_wassert: redefine ZYDIS_ASSERT and ZYDIS_UNREACHABLE to ;
  • unresolved external symbol __imp___stdio_common_vsprintf: use winkernel_mm.* from capstone
  • missing DriverEntry / ALIGN errors -> see this issue
  • unresolved external symbol __imp___stdio_common_vsprintf: add /D _NO_CRT_STDIO_INLINE to cl options in Zydis project

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 20 (17 by maintainers)

Most upvoted comments

Oh yeah, I’d be happy to contribute user/kernel mode Visual Studio project files if there is interest in it (meaning proper ones, not the garbage CMake generates). I know that the feelings w.r.t. doing this are mixed among CMake users, after all CMake can technically make Visual Studio project files so it is duplicating part of the build system. But non-VS users will never know the pain of having to hand-edit 15 XML files to ‘un-CMake’ them.

ZYDIS_WINKERNEL can be inferred from _KERNEL_MODE, which MSVC sets for kernel mode projects (passing /kernel to cl.exe is enough for this, you don’t need a full-blown WDK project).

Some other things I came across that may be of use (I am working on a Windows driver using Zydis at the moment, which is how I found this):

  • ZYDIS_ASSERT is defined to be empty if ZYDIS_WINKERNEL is defined, but this can be replaced with NT_ASSERT(condition), or NT_ASSERT_NOASSUME for asserts that should always execute. This does come at the cost of including <wdm.h>, but you’re going to have a hard time compiling a driver without including wdm.h anyway.
  • The same goes for ZYDIS_UNREACHABLE: __assume(0) compiles in MSVC in both user and kernel mode. But maybe there’s another reason for leaving this macro empty that I’m missing.
  • In CommonTypes.h, it is assumed that having ZYDIS_WINKERNEL without ZYDIS_MSVC is a faulty build configuration. However it has been possible to compile drivers with Clang/LLVM for quite some time 😃 (both Clang/C2 and the ‘proper’ LLVM toolchain.) It’s not something I would recommend for production drivers, but Clang’s static analysis is unparalleled so I make very frequent use of it. Unfortunately the clang-cl frontend does not recognise MSVC’s /kernel switch, so you have to manually define _KERNEL_MODE. Naturally, doing this in an MSVC project results in a fatal error for defining a reserved macro. Sigh…
  • The ‘correct’ way to compile a static library intended for kernel mode use is to create a .vcxproj with PlatformToolset = WindowsKernelModeDriver10.0, DriverType = WDM and ConfigurationType = StaticLibrary. This obviously requires the WDK, is not remotely CMake-compatible and I have trouble believing it provides any actual benefit over simply adding /kernel to the compiler flags for a static library. But, if you try to link a driver against a static library that was not compiled with /kernel, the linker will flat out refuse the .lib as it cannot guarantee that it will work correctly in kernel mode. So that part does matter.

Re: DriverEntry: it is correct that the standard WDK build configuration hijacks the driver entry point to be GsDriverEntry in order to initialize stack cookie support. Counterintuitively it is not enough to disable stack cookies to actually get rid of the forced implant in your driver when you link against KernelBufferOverflowK.lib. So the solution is to (1) disable /GS cookie support, (2) remove KernelBufferOverflowK.lib from the linker inputs and (3) explicitly set the driver entry point to the standard DriverEntry in the linker options under ‘advanced’. This will reduce your driver file size by a few KB free of charge, as well as make it easier to step through in a debugger. Prefast and Clang are much better ways to prevent stack overflows since they add no runtime overhead and they also don’t have the BSOD/kernel panic + reboot cycle overhead that stack cookies do.