System setup for kernel development and debugging

Instructions for setting up a Windows kernel driver development and debugging environment.

© CodeMachine Inc. | codemachine.com | @codemachineinc

This article provides detailed instructions to set up your host system and a Hyper-V guest VM for Windows kernel driver development and debugging. PowerShell scripts which automate most of the setup have been made available for download.

You will need a host system (desktop or laptop) that has a CPU with support for hardware virtualization, at least 8 GB RAM, and at least 50GB of free disk space. The CPU must be fast enough to run at least one VM without any performance degradation. Hyper-V, which is built into Windows 10 Professional and Enterprise editions, will be used as the virtualization software. The kernel drivers you will develop will only run inside the guest virtual machine (VM). Therefore, your host system will not be negatively impacted in any way. The following figure shows the relationship between the host system, the Hyper-V platform, and the guest VM.

FIG#1
Figure 1: Host system and guest VM

Host System

1. Host OS

A recent version of Windows 10 64-bit Professional or Enterprise edition must be installed on the host system and the latest updates must be applied.

2. Internet access

The host system must have reliable internet access for the debugger to download symbols from Microsoft’s public symbol server. The gust VM will NOT connect to the Internet and will be setup in host only networking mode.

3. Source code editor

Windows driver development involves programming in C/C++. Therefore, a good source code editor must be installed on your host system. You can use your favorite source code editor. If you prefer to use Visual Studio Code, you can download Visual Studio Code System Installer 64-bit for Windows 7, 8, 10 and run the installer with default settings.

4. Enterprise Windows Driver Kit (EWDK)

The EWDK contains all the tools required to build and debug kernel software drivers on Windows. Download the EWDK for Windows 10, version 2004 with Visual Studio Build Tools 16.7 and extract the contents of the .ISO file into the folder c:\EWDK. The EWDK uses XCOPY deployment, therefore no installation is necessary. The instructions in the rest of this document assume that you are using the EWDK and it is available at c:\EWDK.

5. Windows Debugger

Download the WinDBG preview from the Windows App Store and install it with default settings.

6. Debugging symbols

Run the following command in an administrative command (cmd.exe) window to set up the environment variable for the debugger to download symbols from Microsoft's public symbol server.

setx _NT_SYMBOL_PATH SRV*c:\symbols*https://msdl.microsoft.com/download/symbols

Hyper-V

NOTE: Steps 7 through 10 have been automated using a PowerShell script. The script will create a Hyper-V Gen 2 VM with the name WINLABVM. If you prefer a different name, you can edit the script to specify a VM name of your choice. If you do so, please use that same name in all steps in this document which has a reference to WINLABVM. If you prefer to continue creating and configuring your VM using this script, download Create-VM-WINLABVM.ps1 to the host. Run the script in an administrative PowerShell command window and proceed to step 11.

7. Enable Hyper-V

In order to create and run Hyper-V VMs, you will have to enable the Hyper-V feature on Windows 10 which is available on the Professional and Enterprise editions of Windows 10. This can be achieved by running the following command in an administrative PowerShell command window.

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

8. Hyper-V RDP access

You will spend a significant amount of time inside the kernel debugger debugging the Hyper-V guest VM. During this time, the guest VM will be stalled and hence any RDP sessions to the guest VM will timeout and disconnect. Hence, "Enhanced Session Mode" must be turned off in Hyper-V. This can be achieved by running the following command in an administrative PowerShell command window.

Set-VMHost -EnableEnhancedSessionMode $False

9. Hyper-V virtual switch configuration

The guest VM must be in a predictable state when you are doing security research. Windows updates must not be applied after installing the guest OS. One way to ensure that Windows updates are not applied is to prevent the guest VM from connecting to the Internet. However, the guest VM must be on a network to share files with the host system. Hyper-V provides the "Internal Network" virtual switch which allows guest-to-host networking. This switch facilitates communication between Hyper-V guests and the Hyper-V host using Automatic Private IP Addressing (APIPA) (i.e. IP address in the 169.254.X.Y range). An "Internal Network" virtual switch can be created by running the following command from an administrative PowerShell command window. The network switch has been named LABNET.

New-VMSwitch -SwitchName "LABNET" -SwitchType Internal

Avoid adding any "External Network" virtual switches as they may cause problems with some DHCP servers.

10. Hyper-V VM configuration

You will need a guest VM with at least 2 virtual CPUs, 2GB virtual RAM, and a 30GB virtual hard drive. You must configure the virtual network adapter to connect to the "Internal Network" virtual switch, turn off UEFI Secure Boot in the guest VM BIOS and configure the VM to boot from a Windows 10 bootable ISO image.

To create such a VM in Hyper-V, run the following set of PowerShell commands from an administrative PowerShell command window. The name of the Hyper-V VM is set to WINLABVM. You can customize the variables $vmname, $switch, $vhdpath, and $isopath, as per your requirements.

$vmname = "WINLABVM"
$switch = "LABNET"
$vhdpath = (Get-VMHost).VirtualHardDiskPath + $vmname + ".vhdx"
$isopath = $env:userprofile + '\Downloads\en_windows_10_business_editions_version_20h2_x64.iso'
$pipename = "\\.\pipe\" + $vmname
New-VHD -Dynamic -SizeBytes 30GB -Path $vhdpath
New-VM -Name $vmname -MemoryStartupBytes 2GB -Generation 2 -SwitchName $switch -VHDPath $vhdpath
$dvddrive = Add-VMDvdDrive -VMName $vmname -Path $isopath 
Set-VM -VMName $vmname -AutomaticCheckpointsEnabled $False -CheckpointType Standard -StaticMemory -ProcessorCount 2
Set-VMFirmware -VMName $vmname -EnableSecureBoot Off -BootOrder $dvddrive
Set-VMCOMPort -VMName $vmname -Number 1 -Path $pipename
Set-VMVideo -VMName $vmname -ResolutionType Maximum -HorizontalResolution 1280 -VerticalResolution 720

11. Connect to the VM console

Since Enhanced Session mode has been disabled, you must connect to the VM is through a local console. This can be achieved by running the following command in an administrative PowerShell or CMD command window.

vmconnect.exe localhost WINLABVM

12. Start the VM

At this point, you can start the VM, so it can boot up from the Windows bootable ISO image to begin the Windows installation process. This can be achieved by running the following command in an administrative PowerShell command window.

Start-VM WINLABVM

VM guest system

13. Guest OS installation

Install the latest Windows 10 64-bit Professional or Enterprise Edition in the guest VM from the OS installation image (.ISO). You can obtain this .ISO from MSDN Platform subscriber downloads or from the Microsoft Evaluation Center. Windows need not be activated. A trial version of Windows will also work fine. When setting up the user account, please specify a password since Windows does not allow shared folders to be accessed with accounts that do not have a password.

NOTE: Steps 14 through 24 have been automated using a PowerShell script. The script will change the computer name of the Guest VM to WINLABVM. If you prefer a different name, you can modify the script file. If you prefer to continue configuring your VM using the script, download Setup-VM-WINLABVM.ps1 to the host. You can execute the script in the Guest VM using the PowerShell Direct service by running the following command in an administrative PowerShell window on the host. When prompted, enter the account name and password which you used while installing Windows in the Guest VM.

$vmcreds = Get-Credential
Invoke-command -VMName WINLABVM -Credential $vmcreds -FilePath Setup-VM-WINLABVM.ps1

Once you have successfully executed the script Setup-VM-WINLABVM.ps1, you can proceed to step 25 in the Setup verification section.

14. Enable PowerShell script execution

You will need to run PowerShell scripts (.ps1) in the guest VM. So, you must enable script execution by running the following command in an administrative PowerShell command window in the guest VM.

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser -Force

15. Enable File and Printer Sharing

As a part of the driver development workflow, you will need to copy files from the host to the guest VM. Therefore, you must enable the Windows Firewall "File and Printer Sharing" rules for the Public network profile which should have been automatically assigned to the network interface in the VM. To enable all the firewall rules for the display group "File And Printer Sharing", run the following command in an administrative PowerShell command window in the guest VM.

Set-NetFirewallRule -Group "@FirewallAPI.dll,-28502" -Profile Public -Enabled true

16. Shared folder setup

Create a folder c:\pub in the guest VM. Share this folder with the host by running the following commands in an administrative PowerShell command window in the guest VM.

New-Item -ItemType "directory" -Path "c:\pub"
New-SmbShare -Name "pub" -Path "c:\pub" -FullAccess "Everyone"

17. Setting up the debugger symbol path

Since the Guest VM will not be connected to the Internet, the symbols for the binaries on the guest required by the debugger and other tools in the guest VM will have to be manually copied from the host to the c:\pub folder. The environment variable _NT_SYMBOL_PATH must be configured to point to c:\pub\sym, in the guest VM.

[System.Environment]::SetEnvironmentVariable('_NT_SYMBOL_PATH', "SRV*c:\pub\sym", 'Machine')

18. Windows Defender exclusions

As a part of the driver development workflow, you will be copying tools from the host to the Guest VM that may be blocked by Windows Defender. Therefore, you must add the shared folder c:\pub to the Windows Defender list of paths excluded from scanning. You can do so by running the following command in an administrative PowerShell command window in the guest VM.

Add-MpPreference -Exclusion Path "c:\pub"

19. Kernel debugging configuration

Examining the system through a kernel debugger is an integral part of driver development workflow. The guest VM must be configured for kernel debugging through the boot configuration database (BCD). The commands listed below create three different boot manager profiles using BCDEDIT:

  • The "original" profile does not have any debugging settings enabled.
  • The "testsign" profile has test-signing enabled.
  • The "debugger" profile has kernel debugging enabled and is the default profile.

Kernel debugging is configured to work over serial port COM1 at a baud rate of 115200. The following commands, which must be run in an Administrative CMD prompt in the Guest VM, configure the system for live kernel debugging.

bcdedit.exe /copy {current} /d "Windows 10 [original]"
bcdedit.exe /set {current} testsigning  ON
bcdedit.exe /copy {current} /d "Windows 10 [testsign]"
bcdedit.exe /debug {current} ON
bcdedit.exe /set {current} description "Windows 10 [debugger]"
bcdedit.exe /dbgsettings serial debugport:1 baudrate:115200
bcdedit.exe /set {current} recoveryenabled No
bcdedit.exe /set {current} bootstatuspolicy IgnoreAllFailures

20. Debug message settings

From your kernel driver, you will call the classic kernel API DbgPrint() to display messages in the kernel debugger. For the kernel debugger to display these messages, the appropriate "Debug Print Filter" must be set in the registry. To enable this registry setting, run the following commands in an administrative PowerShell command window in the guest VM.

New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name 'Debug Print Filter'
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter' -Name 'DEFAULT' -Type DWORD -Value 0xffffffff 

21. Non-Maskable Interrupt Configuration

Run the following commands in an administrative PowerShell command window in the guest VM to configure the guest to bugcheck upon receiving an interrupt (NMI) from the host.

New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -Name 'NMICrashDump' -Type DWORD -Value 1

22. System memory dump settings

Run the following commands in an administrative PowerShell command window in the guest VM to configure the guest OS for memory dump retention, turn off auto-reboot during bug-check, generate complete memory dumps, and always allow memory dumps to be created.

New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -Name 'AlwaysKeepMemoryDump' -Type DWORD -Value 1
Get-WmiObject Win32_OSRecoveryConfiguration | Set-WmiInstance -Arguments @{ AutoReboot=$False }
Get-WmiObject Win32_OSRecoveryConfiguration | Set-WmiInstance -Arguments @{ DebugInfoType=1 }
Get-WmiObject Win32_OSRecoveryConfiguration | Set-WmiInstance -Arguments @{ OverwriteExistingDebugFile=$True }

23. Increase the size of the pagefile

Turn off system-managed pagefile and increase the size of the paging file to accommodate a complete system memory dump.

Get-CimInstance Win32_ComputerSystem | Set-CimInstance -Property @{AutomaticManagedPagefile=$false}
Get-CimInstance Win32_PageFileSetting | Set-CimInstance -Property @{InitialSize=2064;MaximumSize=2064}

24. Renaming the guest OS

Upon installation, Windows automatically assigns a auto-generated computer name to the guest VM. It is best to change the computer name of the Guest to something that is easier to remember, considering that you will use this computer name often to copy files from the host to the guest. You can change the SMB name of the guest to WINLABVM by running the following command in an administrative PowerShell command window in the guest VM. DO NOT RESTART the guest VM yet.

Rename-Computer -NewName "WINLABVM"

Setup verification

25. Shared folder verification

Verify that the share ("pub") is accessible from the host system by attempting to access \\169.254.X.Y\pub from the host. Where 169.254.X.Y is the APIPA IP address assigned to the guest by the internal virtual network switch. You can obtain this IP address by running the following commands in an administrative PowerShell command window in the guest VM.

Get-NetIPAddress -AddressFamily Ipv4 | Select-Object InterfaceAlias, IPv4Address

26. Testing the kernel debugging setup

On the host system, start WinDBG Preview with administrative privileges. Download the workspace settings file WINLABVM.debugtarget. Click on "File" -> "Open Workspace" and load the workspace file WINLABVM.debugtarget. This workspace file configures WinDBG to connect to the named pipe WINLABVM which is mapped to the serial port COM1 of the Guest VM. If you have used a different pipe name for the serial port, then change the following line in WINLABVM.debugtarget.

<Property name="ConnectionString" value="com:port=\\.\pipe\WINLABVM,baud=115200,pipe,reconnect" />

Restart the guest VM. As the guest VM starts up, ensure that WinDBG displays "Kernel Debugger connection established" in the main Window. This indicates a successful connection between WinDBG and the kernel debugging stub (KDCOM.dll) in the guest VM.

Congratulations, you have successfully completed all the setup steps necessary to build, deploy, test and debug kernel mode drivers.