Dela via


Självstudie: Skriva en Hello World Windows-drivrutin (Kernel-Mode Driver Framework)

Den här artikeln beskriver hur du skriver en liten Universal Windows-drivrutin med hjälp av Kernel-Mode Driver Framework (KMDF) och sedan distribuerar och installerar drivrutinen på en separat dator.

Förutsättningar

  • Följ stegen för att installera Windows Driver Kit (WDK). Felsökningsverktyg för Windows ingår när du installerar WDK.

  • Installera Visual Studio 2022. När du installerar Visual Studio 2022 väljer du "Desktoputveckling med C++" som arbetsyta. Under "Enskilda komponenter" kan du lägga till:

    • MSVC v143 – VS 2022 C++ ARM64/ARM64EC Spectre-mitigerade bibliotek (senaste)
    • MSVC v143 – VS 2022 C++ x64/x86 Spectre-reducerade bibliotek (senaste)
    • C++ ATL för de senaste v143-byggverktygen med Spectre Mitigations (ARM64/ARM64EC)
    • C++ ATL för de senaste v143-byggverktygen med Spectre Mitigations (x86 & x64)
    • C++ MFC för de senaste v143-byggverktygen med Spectre Mitigations (ARM64/ARM64EC)
    • C++ MFC för de senaste v143-byggverktygen med Spectre Mitigations (x86 & x64)
    • Windows Driver Kit

Skapa och bygg en drivrutin

  1. Öppna Microsoft Visual Studio. På menyn Arkiv väljer du Nytt > Projekt.

  2. I dialogrutan Skapa ett nytt projekt väljer du C++ i den vänstra listrutan, väljer Windows i den mellersta listrutan och väljer Driver i den högra listrutan.

  3. Välj kernellägesdrivrutin, tom (KMDF) i listan över projekttyper. Välj Nästa.

    Skärmbild av dialogrutan Nytt projekt i Visual Studio med alternativet kärnlägesdrivrutin valt.

    Tips

    Om du inte hittar drivrutinsprojektmallar i Visual Studio installerades inte WDK Visual Studio-tillägget korrekt. Lös problemet genom att starta Visual Studio Installer, välja Ändra, lägga till Windows Driver Kits på fliken enskild komponent och välj Ändra.

  4. I dialogrutan Konfigurera ditt nya projekt anger du "KmdfHelloWorld" i fältet Projektnamn.

    Not

    När du skapar en ny KMDF- eller UMDF-drivrutin måste du välja ett drivrutinsnamn med högst 32 tecken. Den här längdgränsen definieras i wdfglobals.h.

  5. I fältet Plats anger du katalogen där du vill skapa det nya projektet.

  6. Kontrollera Placera lösning och projekt i samma katalog och välj Skapa.

    Skärmbild av dialogrutan Konfigurera det nya projektet i Visual Studio med knappen Skapa markerad.

    Visual Studio skapar ett projekt och en lösning. Du kan se dem i fönstret Solution Explorer. (Om Solution Explorer-fönstret inte visas väljer du Solution Explorer från menyn Visa.) Lösningen har ett drivrutinsprojekt med namnet KmdfHelloWorld.

    Skärmbild av fönstret i Visual Studio Solution Explorer som visar lösningen och det tomma drivrutinsprojektet med namnet KmdfHelloWorld.

  7. I fönstret Solution Explorer högerklickar du på Lösning "KmdfHelloWorld" (1 av 1 projekt) och väljer Configuration Manager. Välj en konfiguration och plattform för drivrutinsprojektet. Välj till exempel Felsök och x64.

  8. I fönstret Solution Explorer högerklickar du på projektet KmdfHelloWorld, väljer Lägg tilloch väljer sedan Nytt objekt.

  9. I dialogrutan Lägg till nytt objekt anger du "Driver.c".

    Notera

    Filnamnstillägget är .c, inte .cpp.

    Välj Lägg till. Filen Driver.c läggs till under Källfiler, som du ser här.

    Skärmbild av fönstret i Visual Studio Solution Explorer som visar filen driver.c som lagts till i drivrutinsprojektet.

Skriv din första drivrutinskod

Nu när du har skapat ditt tomma Hello World-projekt och lagt till källfilen Driver.c skriver du den mest grundläggande kod som krävs för att drivrutinen ska kunna köras genom att implementera två grundläggande funktioner för återanrop av händelser.

  1. I Driver.c börjar du med att inkludera följande rubriker:

    #include <ntddk.h>
    #include <wdf.h>
    

    Tips

    Om du inte kan lägga till Ntddk.höppnar du Configuration –> C/C++ –> Allmänt –> Ytterligare inkluderingskataloger och lägger till C:\Program Files (x86)\Windows Kits\10\Include\<build#>\kmoch ersätter <build#> med lämplig katalog i WDK-installationen.

    Ntddk.h innehåller centrala Windows-kerneldefinitioner för alla drivrutiner, medan Wdf.h innehåller definitioner för drivrutiner baserade på Windows Driver Framework (WDF).

  2. Ange sedan deklarationer för de två återanropen:

    DRIVER_INITIALIZE DriverEntry;
    EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
    
  3. Använd följande kod för att skriva din DriverEntry:

    NTSTATUS 
    DriverEntry(
        _In_ PDRIVER_OBJECT     DriverObject, 
        _In_ PUNICODE_STRING    RegistryPath
    )
    {
        // NTSTATUS variable to record success or failure
        NTSTATUS status = STATUS_SUCCESS;
    
        // Allocate the driver configuration object
        WDF_DRIVER_CONFIG config;
    
        // Print "Hello World" for DriverEntry
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" ));
    
        // Initialize the driver configuration object to register the
        // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd
        WDF_DRIVER_CONFIG_INIT(&config, 
                               KmdfHelloWorldEvtDeviceAdd
                               );
    
        // Finally, create the driver object
        status = WdfDriverCreate(DriverObject, 
                                 RegistryPath, 
                                 WDF_NO_OBJECT_ATTRIBUTES, 
                                 &config, 
                                 WDF_NO_HANDLE
                                 );
        return status;
    }
    

    DriverEntry är startpunkten för alla drivrutiner, som Main() är för många program i användarläge. Jobbet för DriverEntry är att initiera drivrutinsomfattande strukturer och resurser. I det här exemplet skrev du ut "Hello World" för DriverEntry, konfigurerade drivrutinsobjektet för att registrera din EvtDeviceAdd återanropsfunktionens startpunkt och skapade sedan drivrutinsobjektet och returnerade.

    Drivrutinsobjektet fungerar som överordnat objekt för alla andra ramverksobjekt som du kan skapa i drivrutinen, till exempel enhetsobjekt, I/O-köer, timers, spinlocks med mera. Mer information om ramverksobjekt finns i Introduktion till ramverksobjekt.

    Tips

    För DriverEntryrekommenderar vi starkt att du behåller namnet som "DriverEntry" för att hjälpa till med kodanalys och felsökning.

  4. Använd sedan följande kod för att skriva din KmdfHelloWorldEvtDeviceAdd:

    NTSTATUS 
    KmdfHelloWorldEvtDeviceAdd(
        _In_    WDFDRIVER       Driver, 
        _Inout_ PWDFDEVICE_INIT DeviceInit
    )
    {
        // We're not using the driver object,
        // so we need to mark it as unreferenced
        UNREFERENCED_PARAMETER(Driver);
    
        NTSTATUS status;
    
        // Allocate the device object
        WDFDEVICE hDevice;    
    
        // Print "Hello World"
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" ));
    
        // Create the device object
        status = WdfDeviceCreate(&DeviceInit, 
                                 WDF_NO_OBJECT_ATTRIBUTES,
                                 &hDevice
                                 );
        return status;
    }
    

    EvtDeviceAdd anropas av systemet när enheten har anlänt. Dess uppgift är att initiera strukturer och resurser för den enheten. I det här exemplet skrev du ut ett "Hello World"-meddelande för EvtDeviceAdd, skapade enhetsobjektet och returnerade. I andra drivrutiner som du skriver kan du skapa I/O-köer för maskinvaran, konfigurera en enhetskontext lagringsutrymme för enhetsspecifik information eller utföra andra uppgifter som krävs för att förbereda enheten.

    Tips

    För att lägga till återanrop för enheten, observera hur du namngav det med ditt drivrutinsnamn som prefix (KmdfHelloWorldEvtDeviceAdd). I allmänhet rekommenderar vi att du namnger drivrutinsfunktioner på det här sättet för att skilja dem från andra drivrutiners funktioner. DriverEntry är den enda du bör namnge exakt så.

  5. Din fullständiga Driver.c ser nu ut så här:

    #include <ntddk.h>
    #include <wdf.h>
    DRIVER_INITIALIZE DriverEntry;
    EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
    
    NTSTATUS 
    DriverEntry(
        _In_ PDRIVER_OBJECT     DriverObject, 
        _In_ PUNICODE_STRING    RegistryPath
    )
    {
        // NTSTATUS variable to record success or failure
        NTSTATUS status = STATUS_SUCCESS;
    
        // Allocate the driver configuration object
        WDF_DRIVER_CONFIG config;
    
        // Print "Hello World" for DriverEntry
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" ));
    
        // Initialize the driver configuration object to register the
        // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd
        WDF_DRIVER_CONFIG_INIT(&config, 
                               KmdfHelloWorldEvtDeviceAdd
                               );
    
        // Finally, create the driver object
        status = WdfDriverCreate(DriverObject, 
                                 RegistryPath, 
                                 WDF_NO_OBJECT_ATTRIBUTES, 
                                 &config, 
                                 WDF_NO_HANDLE
                                 );
        return status;
    }
    
    NTSTATUS 
    KmdfHelloWorldEvtDeviceAdd(
        _In_    WDFDRIVER       Driver, 
        _Inout_ PWDFDEVICE_INIT DeviceInit
    )
    {
        // We're not using the driver object,
        // so we need to mark it as unreferenced
        UNREFERENCED_PARAMETER(Driver);
    
        NTSTATUS status;
    
        // Allocate the device object
        WDFDEVICE hDevice;    
    
        // Print "Hello World"
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" ));
    
        // Create the device object
        status = WdfDeviceCreate(&DeviceInit, 
                                 WDF_NO_OBJECT_ATTRIBUTES,
                                 &hDevice
                                 );
        return status;
    }
    
  6. Spara Driver.c.

Det här exemplet illustrerar ett grundläggande begrepp för drivrutiner: de är en "samling återanrop" som, när de har initierats, väntar på att bli anropade av systemet när det är något den behöver. Ett systemanrop kan vara en ny enhets ankomsthändelse, en I/O-begäran från ett användarlägesprogram, en händelse för avstängning av systemström, en begäran från en annan drivrutin eller en överraskande borttagningshändelse när en användare oväntat kopplar ur enheten. Lyckligtvis behövde du bara bekymra dig om att skapa drivrutiner och apparater för att säga "Hello World".

Därefter skapar du din drivrutin.

Skapa drivrutinen

  1. I fönstret Solution Explorer högerklickar du på Lösning "KmdfHelloWorld" (1 av 1 projekt) och väljer Configuration Manager. Välj en konfiguration och plattform för drivrutinsprojektet. I den här övningen väljer du Felsöka och x64.

  2. I fönstret Solution Explorer högerklickar du KmdfHelloWorld och väljer Egenskaper. I Wpp Tracing > Alla alternativanger du Kör Wpp-spårning till Nej. Välj Använd och sedan OK.

  3. Skapa drivrutinen genom att välja Build Solution på menyn Build. Visual Studio visar kompileringens framsteg i fönstret Utdata. (Om utdata inte visas väljer du Utdata från menyn Visa.) När du har verifierat att lösningen har byggts framgångsrikt kan du stänga Visual Studio.

  4. Om du vill se den inbyggda drivrutinen går du till mappen KmdfHelloWorld i Utforskaren och sedan till x64\Debug\KmdfHelloWorld. Mappen innehåller:

    • KmdfHelloWorld.sys – drivrutinsfilen i kärnläge
    • KmdfHelloWorld.inf – en informationsfil som Windows använder när du installerar drivrutinen
    • KmdfHelloWorld.cat – en katalogfil som installationsprogrammet använder för att verifiera drivrutinens testsignatur

Tips

Om du ser DriverVer set to a date in the future när du skapar drivrutinen, ändra inställningarna för ditt drivrutinsprojekt så att Inf2Cat ställer in /uselocaltime. Det gör du genom att använda Configuration Properties–>Inf2Cat–>General–>Use Local Time. Nu använder både Stampinf och Inf2Cat lokal tid.

Distribuera drivrutinen

Vanligtvis när du testar och felsöker en drivrutin körs felsökaren och drivrutinen på separata datorer. Datorn som kör felsökningsprogrammet kallas värddatoroch den dator som kör drivrutinen kallas måldator. Måldatorn kallas även testdator.

Hittills har du använt Visual Studio för att skapa en drivrutin på värddatorn. Nu måste du konfigurera en måldator.

  1. Följ anvisningarna i Etablera en dator för drivrutinsdistribution och -testning (WDK 10).

    Tips

    När du följer stegen för att konfigurera måldatorn med hjälp av en nätverkskabel automatiskt bör du anteckna porten och nyckeln. Du använder dem senare i felsökningssteget. I det här exemplet använder du 50000 som port och 1.2.3.4 som nyckel.

    I verkliga felsökningsscenarier för drivrutiner rekommenderar vi att du använder en KDNET-genererad nyckel. Mer information om hur du använder KDNET för att generera en slumpmässig nyckel finns i avsnittet Felsökningsdrivrutiner – Steg-för-steg-labb (Sysvad Kernel Mode).

  2. Öppna lösningen i Visual Studio på värddatorn. Du kan dubbelklicka på lösningsfilen KmdfHelloWorld.sln i mappen KmdfHelloWorld.

  3. Högerklicka på projektet KmdfHelloWorld i Solution Explorer och välj Egenskaper.

  4. Gå till Drivrutinsinstallation > distribution.

  5. För Målenhetsnamnväljer du namnet på den dator som du konfigurerade för testning och felsökning. I den här övningen använder vi en dator med namnet MyTestComputer.

  6. Kontrollera att du testar den senaste versionen av drivrutinen genom att kontrollera Ta bort tidigare drivrutinsversioner innan du distribuerar.

  7. Välj Uppdatering av maskinvaru-ID-drivrutinoch ange maskinvaru-ID för drivrutinen. I den här övningen är maskinvaru-ID:t Root\KmdfHelloWorld. Välj OK.

    Obs.

    I den här övningen identifierar maskinvaru-ID:t inte någon riktig maskinvara. Den identifierar en imaginär enhet som ges en plats i enhetsträdet som ett barn av rotnoden. För riktig maskinvara väljer du inte Uppdatering av maskinvaru-ID-drivrutin, utan välj istället Installera och verifiera. Du ser maskinvaru-ID:t i inf-filen (drivrutinsinformation). I fönstret Solution Explorer går du till KmdfHelloWorld > Driver Filesoch dubbelklickar på KmdfHelloWorld.inf. Maskinvaru-ID:t finns under [Standard.NT$ARCH$].

    [Standard.NT$ARCH$]
    %KmdfHelloWorld.DeviceDesc%=KmdfHelloWorld_Device, Root\KmdfHelloWorld
    
  8. På menyn Build väljer du Deploy Solution. Visual Studio kopierar automatiskt de filer som krävs för att installera och köra drivrutinen till måldatorn. Implementeringen kan ta en minut eller två.

    När du distribuerar en drivrutin kopieras drivrutinsfilerna till mappen %Systemdrive%\drivertest\drivers på testdatorn. Om något går fel under distributionen kan du kontrollera om filerna kopieras till testdatorn. Kontrollera att filerna .inf, .cat, test cert och .sys och andra nödvändiga filer finns i mappen %systemdrive%\drivertest\drivers.

    Mer information om hur du distribuerar drivrutiner finns i Distribuera en drivrutin till en testdator.

Installera drivrutinen

Nu när din Hello World-drivrutin har distribuerats till måldatorn installerar du drivrutinen. När du tidigare etablerade måldatorn med Visual Studio med hjälp av alternativet automatisk konfigurerade Visual Studio måldatorn för att köra testsignerade drivrutiner som en del av etableringsprocessen. Nu behöver du bara installera drivrutinen med devcon-verktyget.

  1. På värddatorn navigerar du till mappen Verktyg i WDK-installationen och letar upp DevCon-verktyget. Titta till exempel i följande mapp:

    C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe

    Kopiera DevCon-verktyget till fjärrdatorn.

  2. Installera drivrutinen på måldatorn genom att navigera till mappen som innehåller drivrutinsfilerna och sedan köra DevCon-verktyget.

    1. Här är den allmänna syntaxen för devcon-verktyget som du ska använda för att installera drivrutinen:

      devcon installera <INF-fil><maskinvaru-ID>

      DEN INF-fil som krävs för att installera den här drivrutinen är KmdfHelloWorld.inf. INF-filen innehåller maskinvaru-ID:t för att installera drivrutinsbinärfilen KmdfHelloWorld.sys. Kom ihåg att maskinvaru-ID:t, som finns i INF-filen, är Root\KmdfHelloWorld.

    2. Öppna ett kommandotolkfönster som administratör. Gå till mappen som innehåller den byggda drivrutinen .sys-filen och ange följande kommando:

      devcon installera kmdfhelloworld.inf root\kmdfhelloworld

      Om du får ett felmeddelande om att devcon inte identifieras, kan du prova att lägga till sökvägen till verktyget devcon. Om du till exempel kopierade den till en mapp på måldatorn med namnet C:\Toolskan du prova att använda följande kommando:

      c:\tools\devcon install kmdfhelloworld.inf root\kmdfhelloworld

      En dialogruta visas som anger att testdrivrutinen är en osignerad drivrutin. Välj Installera drivrutinen ändå för att fortsätta.

      Skärmbild av säkerhetsvarningen som visades under drivrutinsinstallationsprocessen.

Felsöka drivrutinen

Nu när du har installerat kmdfHelloWorld-drivrutinen på måldatorn kopplar du ett felsökningsprogram via fjärranslutning från värddatorn.

  1. Öppna kommandotolken som administratör på värddatorn. Byt till katalogen WinDbg.exe. Du använder x64version av WinDbg.exe från Windows Driver Kit (WDK) som installerades som en del av Windows Kit-installationen. Här är standardsökvägen till WinDbg.exe:

    C:\Program Files (x86)\Windows Kits\10\Debuggers\x64

  2. Starta WinDbg för att ansluta till en kernel-felsökningssession på måldatorn med hjälp av följande kommando. Värdet för porten och nyckeln ska vara samma som det du använde för att konfigurera måldatorn. Du använder 50000 för porten och 1.2.3.4 för nyckeln, de värden som du använde under distributionssteget. Flaggan k anger att det här är en kernel-felsökningssession.

    WinDbg -k net:port=50000,key=1.2.3.4

  3. På menyn Felsöka väljer du Break. Felsökningsprogrammet på värddatorn bryter sig in på måldatorn. I fönstret Felsökningskommando kan du se kommandotolken för kernelfelsökning: kd>.

  4. Nu kan du experimentera med felsökningsprogrammet genom att ange kommandon i kd> prompt. Du kan till exempel prova följande kommandon:

  5. Om du vill låta måldatorn köras igen väljer du från menyn Felsök eller trycker på "g" och trycker sedan på "retur".

  6. Om du vill stoppa felsökningssessionen väljer du Koppla från felsökningsprogrammet från menyn Felsökning.

    Viktig

    Kontrollera att du använder kommandot "go" för att låta måldatorn köras igen innan du avslutar felsökningsprogrammet, eller så fortsätter måldatorn att inte svara på mus- och tangentbordsindata eftersom den fortfarande pratar med felsökningsprogrammet.

En detaljerad stegvis genomgång av felsökningsprocessen för drivrutiner finns i Felsöka universella drivrutiner – Steg för steg-labb (Echo Kernel-Mode).

Mer information om fjärrfelsökning finns i Fjärrfelsökning med WinDbg.

Felsökningsverktyg för Windows

Felsöka universella drivrutiner – Steg för steg-labb (Echo Kernel-Mode)

Skriv din första drivrutin